diff --git a/doc/api/services/compute.rst b/doc/api/services/compute.rst new file mode 100644 index 00000000..9f63b4e3 --- /dev/null +++ b/doc/api/services/compute.rst @@ -0,0 +1,7 @@ +sasctl.services.compute +======================= + +.. automodule:: sasctl._services.compute + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/services/job_definitions.rst b/doc/api/services/job_definitions.rst new file mode 100644 index 00000000..0b50fef6 --- /dev/null +++ b/doc/api/services/job_definitions.rst @@ -0,0 +1,7 @@ +sasctl.services.job_definitions +=============================== + +.. automodule:: sasctl._services.job_definitions + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/services/job_execution.rst b/doc/api/services/job_execution.rst new file mode 100644 index 00000000..a96573d0 --- /dev/null +++ b/doc/api/services/job_execution.rst @@ -0,0 +1,7 @@ +sasctl.services.job_execution +============================= + +.. automodule:: sasctl._services.job_execution + :members: + :undoc-members: + :show-inheritance: diff --git a/src/sasctl/_services/compute.py b/src/sasctl/_services/compute.py new file mode 100644 index 00000000..9ed49f4a --- /dev/null +++ b/src/sasctl/_services/compute.py @@ -0,0 +1,248 @@ +#!/usr/bin/env python +# encoding: utf-8 +# +# Copyright © 2019, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +from .service import Service + + +class Compute(Service): + """The Compute service affords CRUD operations for Compute Contexts. + + A Compute context is analogous to the SAS Application Server from SAS V9. + """ + + _SERVICE_ROOT = '/compute' + + list_contexts, get_context, update_context, delete_context = Service._crud_funcs( + '/contexts' + ) + + list_servers, get_server, _, stop_server = Service._crud_funcs('/servers') + + _, _, _, delete_session = Service._crud_funcs('/sessions') + + @classmethod + def list_sessions(cls, server=None): + """List currently active sessions. + + Parameters + ---------- + server : str or dict, optional + The name or id of the server, or a dictionary representation of the server. If specified, only sessions + for that server will be returned. Otherwise, sessions for all running servers are returned. + + Returns + ------- + list of RestObj + + Raises + ------ + ValueError + If `server` is specified but not found. + + """ + if server is not None: + server_obj = cls.get_server(server) + if server_obj is None: + raise ValueError("Unable to find server '%s'." % server) + uri = '/servers/%s/sessions' % server_obj['id'] + else: + uri = '/sessions' + + results = cls.get(uri) + if isinstance(results, list): + return results + + return [results] + + @classmethod + def get_server_state(cls, server): + """ + + Parameters + ---------- + server : str or dict + The name or id of the server, or a dictionary representation of the server. + + + Returns + ------- + str + {'running', 'stopped'} + + """ + server_obj = cls.get_server(server) + uri = '/servers/%s/state' % server_obj['id'] + + return cls.get(uri) + + @classmethod + def create_job( + cls, + session, + code, + name=None, + description=None, + environment=None, + variables=None, + resources=None, + attributes=None, + ): + """ + + Parameters + ---------- + session : str or dict + code : str + name + description + environment + variables + resources + attributes + + Returns + ------- + + """ + + # TODO: if code is URI pass in codeUri field. + code = code.split('\n') + + uri = '/sessions/%s/jobs' % session['id'] + + # NOTE: variables must be None not [] + resources = resources or [] + environment = environment or {} + attributes = attributes or {} + + data = { + 'version': 3, + 'name': name, + 'description': description, + 'environment': environment, + 'variables': variables, + 'code': code, + 'resources': resources, + 'attributes': attributes, + } + + return cls.post(uri, json=data) + # return cls.request_link(session, 'execute', json=data) + + @classmethod + def create_session(cls, context): + """Create a new session based on an existing Compute Context. + + If a reusable SAS Compute Server is available to handle this session, a new session is created on that SAS + Compute Server. Otherwise, a new SAS Compute Server is created and the new session is created there. + + Parameters + ---------- + context : RestObj + An existing Compute Context as returned by `get_context`. + + Returns + ------- + RestObj + Session details + + """ + context = cls.get_context(context) + + return cls.request_link(context, 'createSession') + + @classmethod + def get_listing(cls, job=None, session=None): + """Retrieve the SAS listing (program output) for a job or an entire session. + + Parameters + ---------- + job : dict, optional + Dictionary representation of an existing job. + session : dict, optional + Dictionary representation of an active session. + + Returns + ------- + list of RestObj + + Raises + ------ + ValueError + If neither `job` nor `session` are provided. + + """ + if job is None and session is None: + raise ValueError("Either a job or a session must be specified.") + + if job: + uri = '/sessions/%s/jobs/%s/listing' % (job['sessionId'], job['id']) + else: + uri = '/sessions/%s/listing' % session['id'] + + return cls.get(uri) + + @classmethod + def get_log(cls, job=None, session=None): + """Retrieve the SAS log for a job or an entire session. + + Parameters + ---------- + job : dict, optional + Dictionary representation of an existing job. + session : dict, optional + Dictionary representation of an active session. + + Returns + ------- + list of RestObj + + Raises + ------ + ValueError + If neither `job` nor `session` are provided. + + """ + if job is None and session is None: + raise ValueError("Either a job or a session must be specified.") + + if job: + uri = '/sessions/%s/jobs/%s/log' % (job['sessionId'], job['id']) + else: + uri = '/sessions/%s/log' % session['id'] + + return cls.get(uri) + + @classmethod + def get_results(cls, job=None, session=None): + """Retrieve the output files for a job or an entire session. + + Parameters + ---------- + job : dict, optional + Dictionary representation of an existing job. + session : dict, optional + Dictionary representation of an active session. + + Returns + ------- + list of RestObj + + Raises + ------ + ValueError + If neither `job` nor `session` are provided. + + """ + if job is None and session is None: + raise ValueError("Either a job or a session must be specified.") + + if job: + uri = '/sessions/%s/jobs/%s/results' % (job['sessionId'], job['id']) + else: + uri = '/sessions/%s/results' % session['id'] + + return cls.get(uri) \ No newline at end of file diff --git a/src/sasctl/_services/job_definitions.py b/src/sasctl/_services/job_definitions.py new file mode 100644 index 00000000..83861020 --- /dev/null +++ b/src/sasctl/_services/job_definitions.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python +# encoding: utf-8 +# +# Copyright © 2019, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +from .service import Service +from ..core import RestObj + + +class JobDefinitions(Service): + """ + Implements the Job Definitions REST API. + + The Job Definitions API manages jobs using the Create, Read, Update, and Delete operations. A Job Definition + is a batch execution that contains a list of input parameters, a job type, and a "code" attribute. A job + definition can run in multiple execution environments, based on the type of the job. + + See Also + -------- + `REST Documentation `_ + """ + + _SERVICE_ROOT = '/jobDefinitions' + + ( + list_definitions, + get_definition, + update_definition, + delete_definition, + ) = Service._crud_funcs('/definitions') + + @classmethod + def create_definition( + cls, + name: str = None, + description: str = None, + type_: str = None, + code: str = None, + parameters=None, + properties: dict = None, + ) -> RestObj: + """Define a new job that can be run in the SAS environment + + Parameters + ---------- + name : str + Job name + description : str + Job description + type_ : {'casl', 'Compute'} + Indicates type of code specified by `code`. Use 'casl' if `code` is CASL or 'Compute' if `code` is + data step. + code : str + Code to be executed whenever this job is run. + parameters : list of dict + List of parameters used by the job. Each entry in the list should be a dictionary with the following items: + - name : str + parameter name + - type : {'character', 'date', 'numeric', 'table'} + parameter type + - label : str + human-readable label for parameter + - required : bool + is it required to specify a parameter value when running the job + - defaultValue : any + parameter's default value if not specified when running job + properties : dict + An arbitrary collection of name/value pairs to associate with the job definition. + + Returns + ------- + RestObj + + """ + + # Convert name:value pairs of properties to separate "name" & "value" fields. + properties = properties or {} + properties = [{'name': k, 'value': v} for k, v in properties.items()] + + parameters = parameters or [] + + clean_parameters = [] + for param in parameters: + param_type = str(param.get('type', '')).upper() + if param_type not in ('TABLE', 'NUMERIC', 'DATE', 'CHARACTER'): + raise ValueError( + "Type '{}' for parameter '{}' is invalid. " + "Expected one of ('TABLE', 'NUMERIC', 'DATE', 'CHARACTER')".format( + param_type, param['name'] + ) + ) + + new_param = { + 'version': 1, + 'name': str(param.get('name', ''))[ + :100 + ], # Max length of 100 characters + 'type': param_type, + 'label': str(param.get('label', ''))[ + :250 + ], # Max length of 250 characters + 'required': bool(param.get('required')), + 'defaultValue': param.get('defaultValue'), + } + clean_parameters.append(new_param) + + definition = { + 'version': 2, + 'name': name, + 'description': description, + 'type': type_, + 'code': code, + 'parameters': clean_parameters, + 'properties': properties, + } + + return cls.post( + '/definitions', + json=definition, + headers={'Accept': 'application/vnd.sas.job.definition+json'}, + ) diff --git a/src/sasctl/_services/job_execution.py b/src/sasctl/_services/job_execution.py new file mode 100644 index 00000000..03195fb2 --- /dev/null +++ b/src/sasctl/_services/job_execution.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# encoding: utf-8 +# +# Copyright © 2019, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + + +from .service import Service +from .job_definitions import JobDefinitions + + +class JobExecution(Service): + """The Job Execution service provides a common mechanism for executing and managing asynchronous jobs. + + This API works in conjunction with the Job Definitions service. You can use the Job Definitions service to create a + definition for any existing Job Execution Provider. You can then execute this definition using the Job Execution + service. + """ + + _SERVICE_ROOT = '/jobExecution' + + list_jobs, get_job, update_job, delete_job = Service._crud_funcs('/jobs') + + @classmethod + def create_job(cls, definition, name=None, description=None, parameters=None): + """Execute a job from an existing job definition. + + Parameters + ---------- + definition : str or RestObj + name : str, optional + Name for the requested job. + description : str, optional + Description of the requested job + parameters : dict, optional + Parameter name/value pairs used to overwrite default parameters defined in job definition. + + Returns + ------- + RestObj + Job request details + + """ + + # Convert id/name into full definition object + definition_obj = JobDefinitions.get_definition(definition) + + if definition_obj is None: + raise ValueError("Unable to find job definition '%s'." % definition) + + uri = cls.get_link(definition_obj, 'self')['uri'] + + parameters = parameters or {} + + data = { + 'name': name, + 'description': description, + 'jobDefinitionUri': uri, + 'arguments': parameters, + } + + headers = { + 'Accept': 'application/vnd.sas.job.execution.job+json', + 'Content-Type': 'application/vnd.sas.job.execution.job.request+json', + } + return cls.post('/jobs', headers=headers, json=data) + + @classmethod + def get_job_state(cls, job): + """Check the status of an existing job. + + Parameters + ---------- + job : str or dict + The name or id of the job, or a dictionary representation of the job. + + Returns + ------- + str + {'pending', 'running', 'canceled', 'completed', failed'} + + """ + + job_obj = cls.get_job(job) + uri = '/jobs/%s/state' % job_obj.id + + return cls.get(uri) diff --git a/src/sasctl/services.py b/src/sasctl/services.py index 5ee3d6bc..3382d5f1 100644 --- a/src/sasctl/services.py +++ b/src/sasctl/services.py @@ -8,12 +8,14 @@ # a single location for importing services. All services should utilize # classmethods allowing them to be used without instantiation from ._services.cas_management import CASManagement as cas_management +from ._services.compute import Compute as compute from ._services.concepts import Concepts as concepts from ._services.data_sources import DataSources as data_sources from ._services.files import Files as files from ._services.folders import Folders as folders -from ._services.microanalytic_score import \ - MicroAnalyticScore as microanalytic_score +from ._services.job_definitions import JobDefinitions as job_definitions +from ._services.job_execution import JobExecution as job_execution +from ._services.microanalytic_score import MicroAnalyticScore as microanalytic_score from ._services.model_management import ModelManagement as model_management from ._services.model_publish import ModelPublish as model_publish from ._services.model_repository import ModelRepository as model_repository @@ -21,8 +23,6 @@ from ._services.relationships import Relationships as relationships from ._services.reports import Reports as reports from ._services.report_images import ReportImages as report_images -from ._services.sentiment_analysis import \ - SentimentAnalysis as sentiment_analysis -from ._services.text_categorization import \ - TextCategorization as text_categorization +from ._services.sentiment_analysis import SentimentAnalysis as sentiment_analysis +from ._services.text_categorization import TextCategorization as text_categorization from ._services.text_parsing import TextParsing as text_parsing diff --git a/tests/cassettes/tests.integration.test_compute.TestJobDefinitions.test_create_job.json b/tests/cassettes/tests.integration.test_compute.TestJobDefinitions.test_create_job.json new file mode 100644 index 00000000..59ae5e8d --- /dev/null +++ b/tests/cassettes/tests.integration.test_compute.TestJobDefinitions.test_create_job.json @@ -0,0 +1,376 @@ +{ + "http_interactions": [ + { + "recorded_at": "2021-09-15T21:33:06", + "request": { + "body": { + "encoding": "utf-8", + "string": "grant_type=password&username=USERNAME&password=*****" + }, + "headers": { + "Accept": [ + "application/json" + ], + "Accept-Encoding": [ + "gzip, deflate" + ], + "Authorization": [ + "Basic [redacted]" + ], + "Connection": [ + "keep-alive" + ], + "Content-Length": [ + "62" + ], + "Content-Type": [ + "application/x-www-form-urlencoded" + ], + "User-Agent": [ + "python-requests/2.22.0" + ] + }, + "method": "POST", + "uri": "https://hostname.com/SASLogon/oauth/token" + }, + "response": { + "body": { + "encoding": "UTF-8", + "string": "{\"access_token\":\"[redacted]\",\"token_type\":\"bearer\",\"id_token\":\"eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vbG9jYWxob3N0L1NBU0xvZ29uL3Rva2VuX2tleXMiLCJraWQiOiJsZWdhY3ktdG9rZW4ta2V5IiwidHlwIjoiSldUIn0.eyJzdWIiOiIyM2I3NDJhOS1jN2IyLTRkNGUtYjBlYy0xZDJhNjdjNjIwOTMiLCJhdWQiOlsic2FzLmVjIl0sImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3QvU0FTTG9nb24vb2F1dGgvdG9rZW4iLCJleHAiOjE2MzE3Nzc1ODcsImlhdCI6MTYzMTc0MTU4NywiYW1yIjpbImV4dCIsInB3ZCJdLCJhenAiOiJzYXMuZWMiLCJzY29wZSI6WyJvcGVuaWQiXSwiZW1haWwiOiJKb25hdGhhbi5XYWxrZXJAc2FzLmNvbSIsInppZCI6InVhYSIsIm9yaWdpbiI6ImxkYXAiLCJqdGkiOiIwZDk3ZGJhMzlkODA0ZGE1ODAwNTFlZDgwNmZhZmQ2YiIsInByZXZpb3VzX2xvZ29uX3RpbWUiOjE2MzE3NDEwODY4MjQsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiY2xpZW50X2lkIjoic2FzLmVjIiwiY2lkIjoic2FzLmVjIiwiZ3JhbnRfdHlwZSI6InBhc3N3b3JkIiwidXNlcl9uYW1lIjoiam96d2FsIiwicmV2X3NpZyI6ImUxODA1M2MiLCJhdXRoX3RpbWUiOjE2MzE3NDE1ODYsInVzZXJfaWQiOiIyM2I3NDJhOS1jN2IyLTRkNGUtYjBlYy0xZDJhNjdjNjIwOTMifQ.EZzKmxWtQltEED6ZPlUCYs1Wfk9VxB525cceP_4MwuytgUfoC4MxY3879oc_KQngXhcFeMfj2lmyJPSadYXFILBY0lRfjZJGHyh6dUvWfrQC2vNAkN_UNbcNr7KdEAwEgEai8NG9fbPWmTtSFuQMrhulBhDedMdPXRiZIA5D3DTwu9SCM0FG9hatBOpeEx-KX-QcTHxtiQM56_GM7ds2ut6byczqhOQmdyleriGYHASZ31VcM3Xc796tZHYNO5nl6WV7SQhKRGnlBD0dXP6K9px13IOSnGXidUZQtqrdWV8xfY9lRwPdfvEm1DbM8tw7v2CATuqFI_qCBv55dN6aRQ\",\"expires_in\":35999,\"scope\":\"esvakmcorionterritoryaccess sviusrs SCR viyapython mismakeordertstval CARYEMPS SAS_Visa_TE esvanemeainstructorconsumers harrisindirectreports rdinformoptin esvakmcrenewalforecastconsumers esvakmcorionoppaccess orcoevasrv02 COESRV tksem AWSSandboxAccount01 cloudacadusers modelmanager uaa.resource otggenrnd RNDSIMSUsers openid domainemps1 gelupdates OR_RD_COE scim.read sasvspusers esvakmcriskconsumers SASAdministrators OneDriveUsers openstackusers CASDiscussion scr_us acoe_server_group scr_ci esvarndperftestconsumers esvakmcorionconsultforecastconsumers intcawebcertreq ANALYSIS cooallamer esvakmcorionriskconsumers CTRYUNITEDSTATES tisurvey gtt_users intcausers BLDGR HADOOP-DEV clients.secret esvaallempsconsumers midena SIMSEdit rdtcaccess Safari_list RDAnnounce DSCIENCE unix_r&d TACCDevelopment SAS_TE AWSsalesenableAccount csatechxchange USemps rdanncauto SIMSView Weekly_Wrap defsusers opsglobalorion DomainEmployees AWS-TAM-Call esvanemeaeduconsumers bryanharrisALLemps esvakmcorionriskaccess exnet.simsview KSA_mail_list SSODLPUsers revegyusercommunity uaa.admin clients.admin AMTX esvakmcorionconsumers AMPSX USSAS esvanemeaeduadmins Skypeplugin TSDATASTORUSERS lanpanfilter exnet.simsedit SalesXchange ORE EMINERS sas92_install techoffice COOALLSTAFF sviadms scr_edu rdengineering allamazonusers R&DUS UDSREPORTS clients.read WWMGlobalBanking atlassiangroups aideas hrsb jaredpetersonallreports BLDALL TESSAUSERS KSA_ADGroup birdrace scr_psd R&D-AAD ITatSAS orclus05 scr_og R5TH scr_ga democenterusers HADOOP-L RE_PYTHON clients.write ts-tba-test scim.write ORCLUS08_USERS\",\"jti\":\"0d97dba39d804da580051ed806fafd6b\"}" + }, + "headers": { + "Cache-Control": [ + "no-store" + ], + "Connection": [ + "Keep-Alive" + ], + "Content-Type": [ + "application/json;charset=UTF-8" + ], + "Date": [ + "Wed, 15 Sep 2021 21:33:07 GMT" + ], + "Keep-Alive": [ + "timeout=5, max=100" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "Apache/2.4" + ], + "Strict-Transport-Security": [ + "max-age=31536000 ; includeSubDomains" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Vary": [ + "User-Agent" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "DENY" + ], + "X-XSS-Protection": [ + "1; mode=block" + ] + }, + "status": { + "code": 200, + "message": "" + }, + "url": "https://hostname.com/SASLogon/oauth/token" + } + }, + { + "recorded_at": "2021-09-15T21:33:07", + "request": { + "body": { + "encoding": "utf-8", + "string": "" + }, + "headers": { + "Accept": [ + "*/*" + ], + "Accept-Encoding": [ + "gzip, deflate" + ], + "Authorization": [ + "Bearer [redacted]" + ], + "Connection": [ + "keep-alive" + ], + "User-Agent": [ + "python-requests/2.22.0" + ] + }, + "method": "GET", + "uri": "https://hostname.com/compute/contexts" + }, + "response": { + "body": { + "encoding": "UTF-8", + "string": "{\"links\":[{\"method\":\"GET\",\"rel\":\"collection\",\"href\":\"/compute/contexts\",\"uri\":\"/compute/contexts\",\"type\":\"application/vnd.sas.collection\",\"itemType\":\"application/vnd.sas.compute.context.summary\"},{\"method\":\"GET\",\"rel\":\"self\",\"href\":\"/compute/contexts?start=0&limit=10\",\"uri\":\"/compute/contexts?start=0&limit=10\",\"type\":\"application/vnd.sas.collection\",\"itemType\":\"application/vnd.sas.compute.context.summary\"},{\"method\":\"POST\",\"rel\":\"createContext\",\"href\":\"/compute/contexts\",\"uri\":\"/compute/contexts\",\"type\":\"application/vnd.sas.compute.context.request\",\"responseType\":\"application/vnd.sas.compute.context.summary\"}],\"name\":\"items\",\"accept\":\"application/vnd.sas.compute.context.summary\",\"start\":0,\"count\":7,\"items\":[{\"createdBy\":\"sas.import9\",\"id\":\"9fbc2c5f-884a-4f01-a941-6ab020d7e7de\",\"links\":[{\"method\":\"GET\",\"rel\":\"self\",\"href\":\"/compute/contexts/9fbc2c5f-884a-4f01-a941-6ab020d7e7de\",\"uri\":\"/compute/contexts/9fbc2c5f-884a-4f01-a941-6ab020d7e7de\",\"type\":\"application/vnd.sas.compute.context\"},{\"method\":\"GET\",\"rel\":\"alternate\",\"href\":\"/compute/contexts/9fbc2c5f-884a-4f01-a941-6ab020d7e7de\",\"uri\":\"/compute/contexts/9fbc2c5f-884a-4f01-a941-6ab020d7e7de\",\"type\":\"application/vnd.sas.compute.context.summary\"},{\"method\":\"DELETE\",\"rel\":\"delete\",\"href\":\"/compute/contexts/9fbc2c5f-884a-4f01-a941-6ab020d7e7de\",\"uri\":\"/compute/contexts/9fbc2c5f-884a-4f01-a941-6ab020d7e7de\"},{\"method\":\"POST\",\"rel\":\"createSession\",\"href\":\"/compute/contexts/9fbc2c5f-884a-4f01-a941-6ab020d7e7de/sessions\",\"uri\":\"/compute/contexts/9fbc2c5f-884a-4f01-a941-6ab020d7e7de/sessions\",\"type\":\"application/vnd.sas.compute.session.request\",\"responseType\":\"application/vnd.sas.compute.session\"}],\"version\":2,\"name\":\"Import 9 service compute context\"},{\"createdBy\":\"sas.casFormats\",\"id\":\"2cd8325f-f4ca-4c8d-8aed-90dd9ea78d0a\",\"links\":[{\"method\":\"GET\",\"rel\":\"self\",\"href\":\"/compute/contexts/2cd8325f-f4ca-4c8d-8aed-90dd9ea78d0a\",\"uri\":\"/compute/contexts/2cd8325f-f4ca-4c8d-8aed-90dd9ea78d0a\",\"type\":\"application/vnd.sas.compute.context\"},{\"method\":\"GET\",\"rel\":\"alternate\",\"href\":\"/compute/contexts/2cd8325f-f4ca-4c8d-8aed-90dd9ea78d0a\",\"uri\":\"/compute/contexts/2cd8325f-f4ca-4c8d-8aed-90dd9ea78d0a\",\"type\":\"application/vnd.sas.compute.context.summary\"},{\"method\":\"DELETE\",\"rel\":\"delete\",\"href\":\"/compute/contexts/2cd8325f-f4ca-4c8d-8aed-90dd9ea78d0a\",\"uri\":\"/compute/contexts/2cd8325f-f4ca-4c8d-8aed-90dd9ea78d0a\"},{\"method\":\"POST\",\"rel\":\"createSession\",\"href\":\"/compute/contexts/2cd8325f-f4ca-4c8d-8aed-90dd9ea78d0a/sessions\",\"uri\":\"/compute/contexts/2cd8325f-f4ca-4c8d-8aed-90dd9ea78d0a/sessions\",\"type\":\"application/vnd.sas.compute.session.request\",\"responseType\":\"application/vnd.sas.compute.session\"}],\"version\":2,\"name\":\"CAS Formats service compute context\"},{\"createdBy\":\"sas.SASJobExecution\",\"id\":\"a72ed0cc-9fa7-476f-9c3e-7b07b96f5636\",\"links\":[{\"method\":\"GET\",\"rel\":\"self\",\"href\":\"/compute/contexts/a72ed0cc-9fa7-476f-9c3e-7b07b96f5636\",\"uri\":\"/compute/contexts/a72ed0cc-9fa7-476f-9c3e-7b07b96f5636\",\"type\":\"application/vnd.sas.compute.context\"},{\"method\":\"GET\",\"rel\":\"alternate\",\"href\":\"/compute/contexts/a72ed0cc-9fa7-476f-9c3e-7b07b96f5636\",\"uri\":\"/compute/contexts/a72ed0cc-9fa7-476f-9c3e-7b07b96f5636\",\"type\":\"application/vnd.sas.compute.context.summary\"},{\"method\":\"DELETE\",\"rel\":\"delete\",\"href\":\"/compute/contexts/a72ed0cc-9fa7-476f-9c3e-7b07b96f5636\",\"uri\":\"/compute/contexts/a72ed0cc-9fa7-476f-9c3e-7b07b96f5636\"},{\"method\":\"POST\",\"rel\":\"createSession\",\"href\":\"/compute/contexts/a72ed0cc-9fa7-476f-9c3e-7b07b96f5636/sessions\",\"uri\":\"/compute/contexts/a72ed0cc-9fa7-476f-9c3e-7b07b96f5636/sessions\",\"type\":\"application/vnd.sas.compute.session.request\",\"responseType\":\"application/vnd.sas.compute.session\"}],\"version\":2,\"name\":\"SAS Job Execution compute context\"},{\"createdBy\":\"sas.modelPublish\",\"id\":\"93e83a20-d0ad-4ea7-afe1-6057eed2126b\",\"links\":[{\"method\":\"GET\",\"rel\":\"self\",\"href\":\"/compute/contexts/93e83a20-d0ad-4ea7-afe1-6057eed2126b\",\"uri\":\"/compute/contexts/93e83a20-d0ad-4ea7-afe1-6057eed2126b\",\"type\":\"application/vnd.sas.compute.context\"},{\"method\":\"GET\",\"rel\":\"alternate\",\"href\":\"/compute/contexts/93e83a20-d0ad-4ea7-afe1-6057eed2126b\",\"uri\":\"/compute/contexts/93e83a20-d0ad-4ea7-afe1-6057eed2126b\",\"type\":\"application/vnd.sas.compute.context.summary\"},{\"method\":\"DELETE\",\"rel\":\"delete\",\"href\":\"/compute/contexts/93e83a20-d0ad-4ea7-afe1-6057eed2126b\",\"uri\":\"/compute/contexts/93e83a20-d0ad-4ea7-afe1-6057eed2126b\"},{\"method\":\"POST\",\"rel\":\"createSession\",\"href\":\"/compute/contexts/93e83a20-d0ad-4ea7-afe1-6057eed2126b/sessions\",\"uri\":\"/compute/contexts/93e83a20-d0ad-4ea7-afe1-6057eed2126b/sessions\",\"type\":\"application/vnd.sas.compute.session.request\",\"responseType\":\"application/vnd.sas.compute.session\"}],\"version\":2,\"name\":\"SAS Model Manager compute context\"},{\"createdBy\":\"sas.SASStudioV\",\"id\":\"1f42f4d3-de57-4d72-b0b4-0057250824ab\",\"links\":[{\"method\":\"GET\",\"rel\":\"self\",\"href\":\"/compute/contexts/1f42f4d3-de57-4d72-b0b4-0057250824ab\",\"uri\":\"/compute/contexts/1f42f4d3-de57-4d72-b0b4-0057250824ab\",\"type\":\"application/vnd.sas.compute.context\"},{\"method\":\"GET\",\"rel\":\"alternate\",\"href\":\"/compute/contexts/1f42f4d3-de57-4d72-b0b4-0057250824ab\",\"uri\":\"/compute/contexts/1f42f4d3-de57-4d72-b0b4-0057250824ab\",\"type\":\"application/vnd.sas.compute.context.summary\"},{\"method\":\"DELETE\",\"rel\":\"delete\",\"href\":\"/compute/contexts/1f42f4d3-de57-4d72-b0b4-0057250824ab\",\"uri\":\"/compute/contexts/1f42f4d3-de57-4d72-b0b4-0057250824ab\"},{\"method\":\"POST\",\"rel\":\"createSession\",\"href\":\"/compute/contexts/1f42f4d3-de57-4d72-b0b4-0057250824ab/sessions\",\"uri\":\"/compute/contexts/1f42f4d3-de57-4d72-b0b4-0057250824ab/sessions\",\"type\":\"application/vnd.sas.compute.session.request\",\"responseType\":\"application/vnd.sas.compute.session\"}],\"version\":2,\"name\":\"SAS Studio compute context\"},{\"createdBy\":\"sas.dataMining\",\"id\":\"073b25d4-3107-4b67-b727-1c0253027a80\",\"links\":[{\"method\":\"GET\",\"rel\":\"self\",\"href\":\"/compute/contexts/073b25d4-3107-4b67-b727-1c0253027a80\",\"uri\":\"/compute/contexts/073b25d4-3107-4b67-b727-1c0253027a80\",\"type\":\"application/vnd.sas.compute.context\"},{\"method\":\"GET\",\"rel\":\"alternate\",\"href\":\"/compute/contexts/073b25d4-3107-4b67-b727-1c0253027a80\",\"uri\":\"/compute/contexts/073b25d4-3107-4b67-b727-1c0253027a80\",\"type\":\"application/vnd.sas.compute.context.summary\"},{\"method\":\"DELETE\",\"rel\":\"delete\",\"href\":\"/compute/contexts/073b25d4-3107-4b67-b727-1c0253027a80\",\"uri\":\"/compute/contexts/073b25d4-3107-4b67-b727-1c0253027a80\"},{\"method\":\"POST\",\"rel\":\"createSession\",\"href\":\"/compute/contexts/073b25d4-3107-4b67-b727-1c0253027a80/sessions\",\"uri\":\"/compute/contexts/073b25d4-3107-4b67-b727-1c0253027a80/sessions\",\"type\":\"application/vnd.sas.compute.session.request\",\"responseType\":\"application/vnd.sas.compute.session\"}],\"version\":2,\"name\":\"Data Mining compute context\"},{\"createdBy\":\"sas.forecastingGateway\",\"id\":\"31c1321a-9b12-4369-93ed-b461d6331d03\",\"links\":[{\"method\":\"GET\",\"rel\":\"self\",\"href\":\"/compute/contexts/31c1321a-9b12-4369-93ed-b461d6331d03\",\"uri\":\"/compute/contexts/31c1321a-9b12-4369-93ed-b461d6331d03\",\"type\":\"application/vnd.sas.compute.context\"},{\"method\":\"GET\",\"rel\":\"alternate\",\"href\":\"/compute/contexts/31c1321a-9b12-4369-93ed-b461d6331d03\",\"uri\":\"/compute/contexts/31c1321a-9b12-4369-93ed-b461d6331d03\",\"type\":\"application/vnd.sas.compute.context.summary\"},{\"method\":\"DELETE\",\"rel\":\"delete\",\"href\":\"/compute/contexts/31c1321a-9b12-4369-93ed-b461d6331d03\",\"uri\":\"/compute/contexts/31c1321a-9b12-4369-93ed-b461d6331d03\"},{\"method\":\"POST\",\"rel\":\"createSession\",\"href\":\"/compute/contexts/31c1321a-9b12-4369-93ed-b461d6331d03/sessions\",\"uri\":\"/compute/contexts/31c1321a-9b12-4369-93ed-b461d6331d03/sessions\",\"type\":\"application/vnd.sas.compute.session.request\",\"responseType\":\"application/vnd.sas.compute.session\"}],\"version\":2,\"name\":\"SAS Visual Forecasting compute context\"}],\"limit\":10,\"version\":2}" + }, + "headers": { + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Connection": [ + "Keep-Alive" + ], + "Content-Security-Policy": [ + "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' *.sas.com blob: data:; style-src 'self' 'unsafe-inline'; child-src 'self' blob: data: mailto:;" + ], + "Content-Type": [ + "application/vnd.sas.collection+json;charset=UTF-8" + ], + "Date": [ + "Wed, 15 Sep 2021 21:33:07 GMT" + ], + "Expires": [ + "0" + ], + "Keep-Alive": [ + "timeout=5, max=99" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "Apache/2.4" + ], + "Strict-Transport-Security": [ + "max-age=31536000 ; includeSubDomains" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Vary": [ + "User-Agent" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-XSS-Protection": [ + "1; mode=block" + ] + }, + "status": { + "code": 200, + "message": "" + }, + "url": "https://hostname.com/compute/contexts" + } + }, + { + "recorded_at": "2021-09-15T21:33:08", + "request": { + "body": { + "encoding": "utf-8", + "string": "" + }, + "headers": { + "Accept": [ + "*/*" + ], + "Accept-Encoding": [ + "gzip, deflate" + ], + "Authorization": [ + "Bearer [redacted]" + ], + "Connection": [ + "keep-alive" + ], + "Content-Length": [ + "0" + ], + "User-Agent": [ + "python-requests/2.22.0" + ] + }, + "method": "POST", + "uri": "https://hostname.com/compute/contexts/9fbc2c5f-884a-4f01-a941-6ab020d7e7de/sessions" + }, + "response": { + "body": { + "encoding": null, + "string": "{\"owner\":\"USERNAME\",\"state\":\"pending\",\"attributes\":{\"homeDirectory\":\"/opt/sas/viya/config/var/run/compsrv/default/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8\",\"sessionInactiveTimeout\":900},\"serverId\":\"d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8\",\"creationTimeStamp\":\"2021-09-15T21:33:08.000Z\",\"applicationName\":\"sas.ec\",\"sessionConditionCode\":0,\"stateElapsedTime\":0,\"id\":\"d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\",\"links\":[{\"method\":\"GET\",\"rel\":\"self\",\"href\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\",\"uri\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\",\"type\":\"application/vnd.sas.compute.session\"},{\"method\":\"GET\",\"rel\":\"alternate\",\"href\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\",\"uri\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\",\"type\":\"application/vnd.sas.compute.session.summary\"},{\"method\":\"GET\",\"rel\":\"state\",\"href\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/state\",\"uri\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/state\",\"type\":\"text/plain\"},{\"method\":\"PUT\",\"rel\":\"cancel\",\"href\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/state?value=canceled\",\"uri\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/state?value=canceled\"},{\"method\":\"DELETE\",\"rel\":\"delete\",\"href\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\",\"uri\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\"},{\"method\":\"POST\",\"rel\":\"execute\",\"href\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/jobs\",\"uri\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/jobs\",\"type\":\"application/vnd.sas.compute.job.request\",\"responseType\":\"application/vnd.sas.compute.job\"},{\"method\":\"GET\",\"rel\":\"jobs\",\"href\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/jobs\",\"uri\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/jobs\",\"type\":\"application/vnd.sas.collection\",\"itemType\":\"application/vnd.sas.compute.job\"},{\"method\":\"GET\",\"rel\":\"files\",\"href\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/filerefs\",\"uri\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/filerefs\",\"type\":\"application/vnd.sas.collection\",\"itemType\":\"application/vnd.sas.compute.fileref.summary\"},{\"method\":\"POST\",\"rel\":\"assign\",\"href\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/filerefs\",\"uri\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/filerefs\",\"type\":\"application/vnd.sas.compute.fileref.request\",\"responseType\":\"application/vnd.sas.compute.fileref\"},{\"method\":\"GET\",\"rel\":\"librefs\",\"href\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/data\",\"uri\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/data\",\"type\":\"application/vnd.sas.collection\",\"itemType\":\"application/vnd.sas.compute.library.summary\"},{\"method\":\"GET\",\"rel\":\"log\",\"href\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/log\",\"uri\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/log\",\"type\":\"application/vnd.sas.collection\",\"itemType\":\"application/vnd.sas.compute.log.line\"},{\"method\":\"GET\",\"rel\":\"listing\",\"href\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/listing\",\"uri\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/listing\",\"type\":\"application/vnd.sas.collection\",\"itemType\":\"application/vnd.sas.compute.log.line\"},{\"method\":\"GET\",\"rel\":\"results\",\"href\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/results\",\"uri\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/results\",\"type\":\"application/vnd.sas.collection\",\"itemType\":\"application/vnd.sas.compute.result\"},{\"method\":\"GET\",\"rel\":\"variables\",\"href\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/variables\",\"uri\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/variables\",\"type\":\"application/vnd.sas.collection\",\"itemType\":\"application/vnd.sas.compute.session.variable\"},{\"method\":\"GET\",\"rel\":\"engines\",\"href\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/engines\",\"uri\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/engines\",\"type\":\"application/vnd.sas.collection\",\"itemType\":\"application/vnd.sas.data.engine\"},{\"method\":\"GET\",\"rel\":\"getFiles\",\"href\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/files\",\"uri\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/files\",\"type\":\"application/vnd.sas.compute.file.properties\"},{\"method\":\"GET\",\"rel\":\"getOption\",\"href\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/options/{optionName}\",\"uri\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/options/{optionName}\",\"type\":\"text/plain\"},{\"method\":\"PUT\",\"rel\":\"updateOption\",\"href\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/options/{optionName}\",\"uri\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/options/{optionName}\",\"type\":\"text/plain\",\"responseType\":\"text/plain\"},{\"method\":\"GET\",\"rel\":\"formats\",\"href\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/formats\",\"uri\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/formats\",\"type\":\"application/vnd.sas.collection\",\"itemType\":\"application/vnd.sas.format.summary\"},{\"method\":\"GET\",\"rel\":\"informats\",\"href\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/informats\",\"uri\":\"/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/informats\",\"type\":\"application/vnd.sas.collection\",\"itemType\":\"application/vnd.sas.format.summary\"}],\"version\":1}" + }, + "headers": { + "Cache-Control": [ + "no-store" + ], + "Connection": [ + "Keep-Alive" + ], + "Content-Security-Policy": [ + "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' *.sas.com blob: data:; style-src 'self' 'unsafe-inline'; child-src 'self' blob: data: mailto:;" + ], + "Content-Type": [ + "application/vnd.sas.compute.session+json; version=1" + ], + "Date": [ + "Wed, 15 Sep 2021 21:33:08 GMT" + ], + "ETag": [ + "\"j6a571x48z\"" + ], + "Keep-Alive": [ + "timeout=5, max=98" + ], + "Location": [ + "/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000" + ], + "Origin": [ + "https://hostname.com:35273" + ], + "Pragma": [ + "no-cache" + ], + "Public": [ + "GET, PUT, HEAD, POST, DELETE, TRACE, OPTIONS, PATCH" + ], + "Server": [ + "Apache/2.4" + ], + "Strict-Transport-Security": [ + "max-age=31536000 ; includeSubDomains" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Vary": [ + "User-Agent" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-XSS-Protection": [ + "1; mode=block" + ] + }, + "status": { + "code": 201, + "message": "" + }, + "url": "https://hostname.com/compute/contexts/9fbc2c5f-884a-4f01-a941-6ab020d7e7de/sessions" + } + }, + { + "recorded_at": "2021-09-15T21:33:08", + "request": { + "body": { + "encoding": "utf-8", + "string": "{\"version\": 3, \"name\": \"sasctl test job\", \"description\": \"Test job execution from sasctl\", \"environment\": {}, \"variables\": null, \"code\": [\"\", \" ods html style=HTMLBlue;\", \" proc print data=sashelp.class(OBS=5); \", \" run; \", \" quit;\", \" ods html close;\", \" \"], \"resources\": [], \"attributes\": {}}" + }, + "headers": { + "Accept": [ + "*/*" + ], + "Accept-Encoding": [ + "gzip, deflate" + ], + "Authorization": [ + "Bearer [redacted]" + ], + "Connection": [ + "keep-alive" + ], + "Content-Length": [ + "336" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "python-requests/2.22.0" + ] + }, + "method": "POST", + "uri": "https://hostname.com/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/jobs" + }, + "response": { + "body": { + "encoding": null, + "string": "{\"creationTimeStamp\":\"2021-09-15T21:33:08Z\",\"id\":\"D9D29C99-7099-1D45-8760-FAD0A5EBDFDA\",\"links\":[{\"href\":\"\\/compute\\/sessions\\/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\\/jobs\\/D9D29C99-7099-1D45-8760-FAD0A5EBDFDA\",\"method\":\"GET\",\"rel\":\"self\",\"type\":\"application\\/vnd.sas.compute.job\",\"uri\":\"\\/compute\\/sessions\\/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\\/jobs\\/D9D29C99-7099-1D45-8760-FAD0A5EBDFDA\"},{\"href\":\"\\/compute\\/sessions\\/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\\/jobs\\/D9D29C99-7099-1D45-8760-FAD0A5EBDFDA\\/state\",\"method\":\"GET\",\"rel\":\"state\",\"type\":\"text\\/plain\",\"uri\":\"\\/compute\\/sessions\\/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\\/jobs\\/D9D29C99-7099-1D45-8760-FAD0A5EBDFDA\\/state\"},{\"href\":\"\\/compute\\/sessions\\/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\\/jobs\\/D9D29C99-7099-1D45-8760-FAD0A5EBDFDA\\/state?value=canceled\",\"method\":\"PUT\",\"rel\":\"cancel\",\"uri\":\"\\/compute\\/sessions\\/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\\/jobs\\/D9D29C99-7099-1D45-8760-FAD0A5EBDFDA\\/state?value=canceled\"},{\"href\":\"\\/compute\\/sessions\\/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\\/jobs\\/D9D29C99-7099-1D45-8760-FAD0A5EBDFDA\",\"method\":\"DELETE\",\"rel\":\"delete\",\"uri\":\"\\/compute\\/sessions\\/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\\/jobs\\/D9D29C99-7099-1D45-8760-FAD0A5EBDFDA\"},{\"href\":\"\\/compute\\/sessions\\/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\\/jobs\\/D9D29C99-7099-1D45-8760-FAD0A5EBDFDA\\/log\",\"itemType\":\"application\\/vnd.sas.compute.log.line\",\"method\":\"GET\",\"rel\":\"log\",\"type\":\"application\\/vnd.sas.collection\",\"uri\":\"\\/compute\\/sessions\\/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\\/jobs\\/D9D29C99-7099-1D45-8760-FAD0A5EBDFDA\\/log\"},{\"href\":\"\\/compute\\/sessions\\/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\\/jobs\\/D9D29C99-7099-1D45-8760-FAD0A5EBDFDA\\/listing\",\"itemType\":\"application\\/vnd.sas.compute.log.line\",\"method\":\"GET\",\"rel\":\"listing\",\"type\":\"application\\/vnd.sas.collection\",\"uri\":\"\\/compute\\/sessions\\/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\\/jobs\\/D9D29C99-7099-1D45-8760-FAD0A5EBDFDA\\/listing\"},{\"href\":\"\\/compute\\/sessions\\/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\\/jobs\\/D9D29C99-7099-1D45-8760-FAD0A5EBDFDA\\/results\",\"itemType\":\"application\\/vnd.sas.compute.result\",\"method\":\"GET\",\"rel\":\"results\",\"type\":\"application\\/vnd.sas.collection\",\"uri\":\"\\/compute\\/sessions\\/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\\/jobs\\/D9D29C99-7099-1D45-8760-FAD0A5EBDFDA\\/results\"},{\"href\":\"\\/compute\\/sessions\\/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\",\"method\":\"GET\",\"rel\":\"up\",\"type\":\"application\\/vnd.sas.compute.session\",\"uri\":\"\\/compute\\/sessions\\/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\"}],\"sessionId\":\"d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000\",\"state\":\"pending\",\"stateElapsedTime\":0,\"version\":1}" + }, + "headers": { + "Cache-Control": [ + "no-store" + ], + "Connection": [ + "Keep-Alive" + ], + "Content-Length": [ + "2754" + ], + "Content-Security-Policy": [ + "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' *.sas.com blob: data:; style-src 'self' 'unsafe-inline'; child-src 'self' blob: data: mailto:;" + ], + "Content-Type": [ + "application/vnd.sas.compute.job+json; version=1" + ], + "Date": [ + "Wed, 15 Sep 2021 21:33:08 GMT" + ], + "ETag": [ + "\"j6a571zq5j\"" + ], + "Keep-Alive": [ + "timeout=5, max=97" + ], + "Location": [ + "/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/jobs/D9D29C99-7099-1D45-8760-FAD0A5EBDFDA" + ], + "Origin": [ + "https://hostname.com:35273" + ], + "Pragma": [ + "no-cache" + ], + "Public": [ + "GET, PUT, HEAD, POST, DELETE, TRACE, OPTIONS, PATCH" + ], + "Server": [ + "Apache/2.4" + ], + "Strict-Transport-Security": [ + "max-age=31536000 ; includeSubDomains" + ], + "Vary": [ + "User-Agent" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-XSS-Protection": [ + "1; mode=block" + ] + }, + "status": { + "code": 201, + "message": "" + }, + "url": "https://hostname.com/compute/sessions/d5dbd7dc-d84e-4535-aa1c-94c459e6eeb8-ses0000/jobs" + } + } + ], + "recorded_with": "betamax/0.8.1" +} \ No newline at end of file diff --git a/tests/cassettes/tests.integration.test_compute.TestJobDefinitions.test_get_listing.json b/tests/cassettes/tests.integration.test_compute.TestJobDefinitions.test_get_listing.json new file mode 100644 index 00000000..62eaea8b --- /dev/null +++ b/tests/cassettes/tests.integration.test_compute.TestJobDefinitions.test_get_listing.json @@ -0,0 +1,91 @@ +{ + "http_interactions": [ + { + "recorded_at": "2021-09-16T16:34:55", + "request": { + "body": { + "encoding": "utf-8", + "string": "grant_type=password&username=USERNAME&password=*****" + }, + "headers": { + "Accept": [ + "application/json" + ], + "Accept-Encoding": [ + "gzip, deflate" + ], + "Authorization": [ + "Basic [redacted]" + ], + "Connection": [ + "keep-alive" + ], + "Content-Length": [ + "62" + ], + "Content-Type": [ + "application/x-www-form-urlencoded" + ], + "User-Agent": [ + "python-requests/2.22.0" + ] + }, + "method": "POST", + "uri": "https://hostname.com/SASLogon/oauth/token" + }, + "response": { + "body": { + "encoding": "UTF-8", + "string": "{\"access_token\":\"[redacted]\",\"token_type\":\"bearer\",\"id_token\":\"eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vbG9jYWxob3N0L1NBU0xvZ29uL3Rva2VuX2tleXMiLCJraWQiOiJsZWdhY3ktdG9rZW4ta2V5IiwidHlwIjoiSldUIn0.eyJzdWIiOiIyM2I3NDJhOS1jN2IyLTRkNGUtYjBlYy0xZDJhNjdjNjIwOTMiLCJhdWQiOlsic2FzLmVjIl0sImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3QvU0FTTG9nb24vb2F1dGgvdG9rZW4iLCJleHAiOjE2MzE4NDYwOTUsImlhdCI6MTYzMTgxMDA5NSwiYW1yIjpbImV4dCIsInB3ZCJdLCJhenAiOiJzYXMuZWMiLCJzY29wZSI6WyJvcGVuaWQiXSwiZW1haWwiOiJKb25hdGhhbi5XYWxrZXJAc2FzLmNvbSIsInppZCI6InVhYSIsIm9yaWdpbiI6ImxkYXAiLCJqdGkiOiJkNTlkNjE5NmVmMmQ0YjZiODAwZWYyMWY3NzkzYzBkZiIsInByZXZpb3VzX2xvZ29uX3RpbWUiOjE2MzE4MDk5ODExNzAsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiY2xpZW50X2lkIjoic2FzLmVjIiwiY2lkIjoic2FzLmVjIiwiZ3JhbnRfdHlwZSI6InBhc3N3b3JkIiwidXNlcl9uYW1lIjoiam96d2FsIiwicmV2X3NpZyI6ImUxODA1M2MiLCJhdXRoX3RpbWUiOjE2MzE4MTAwOTUsInVzZXJfaWQiOiIyM2I3NDJhOS1jN2IyLTRkNGUtYjBlYy0xZDJhNjdjNjIwOTMifQ.Xte8tOJu1fUrAkFIM72MIcaw76dBqY7U3M9u1FotpkuEvxrYP48BxI7CkSQwxC38f0xBCir0_q5sFPAxyCWfsBTM7Ockj9TyV4AAUxJPnFtm2_Q4fcKYWPwPwb3DcNNWxLW-tcoqA7XZ9HRLaxui1yEoJtRYrDpGRKhWmS-y4oGXD9dQsSGwQgy3Zno0XbqNPUkQRiLNP3sQVvUzI88tbK1-Q6MZ-RhGIRjYGjMjOxDG71ZQ58pDUETux5RxxoXPns0ttw7Lo9M3NQnQZUCVH9CbNBnR21yH9a-yI06nPfT3w4ADWHMV2rFGvwrQL-21phBmmwR7ZiJY5LgNL7_SVg\",\"expires_in\":35999,\"scope\":\"esvakmcorionterritoryaccess sviusrs SCR viyapython mismakeordertstval CARYEMPS SAS_Visa_TE esvanemeainstructorconsumers harrisindirectreports rdinformoptin esvakmcrenewalforecastconsumers esvakmcorionoppaccess orcoevasrv02 COESRV tksem AWSSandboxAccount01 cloudacadusers modelmanager uaa.resource otggenrnd RNDSIMSUsers openid domainemps1 gelupdates OR_RD_COE scim.read sasvspusers esvakmcriskconsumers SASAdministrators OneDriveUsers openstackusers CASDiscussion scr_us acoe_server_group scr_ci esvarndperftestconsumers esvakmcorionconsultforecastconsumers intcawebcertreq ANALYSIS cooallamer esvakmcorionriskconsumers CTRYUNITEDSTATES tisurvey gtt_users intcausers BLDGR HADOOP-DEV clients.secret esvaallempsconsumers midena SIMSEdit rdtcaccess Safari_list RDAnnounce DSCIENCE unix_r&d TACCDevelopment SAS_TE AWSsalesenableAccount csatechxchange USemps rdanncauto SIMSView Weekly_Wrap defsusers opsglobalorion DomainEmployees AWS-TAM-Call esvanemeaeduconsumers bryanharrisALLemps esvakmcorionriskaccess exnet.simsview KSA_mail_list SSODLPUsers revegyusercommunity uaa.admin clients.admin AMTX esvakmcorionconsumers AMPSX USSAS esvanemeaeduadmins Skypeplugin TSDATASTORUSERS lanpanfilter exnet.simsedit SalesXchange ORE EMINERS sas92_install techoffice COOALLSTAFF sviadms scr_edu rdengineering allamazonusers R&DUS UDSREPORTS clients.read WWMGlobalBanking atlassiangroups aideas hrsb jaredpetersonallreports BLDALL TESSAUSERS KSA_ADGroup birdrace scr_psd R&D-AAD ITatSAS orclus05 scr_og R5TH scr_ga democenterusers HADOOP-L RE_PYTHON clients.write ts-tba-test scim.write ORCLUS08_USERS\",\"jti\":\"d59d6196ef2d4b6b800ef21f7793c0df\"}" + }, + "headers": { + "Cache-Control": [ + "no-store" + ], + "Connection": [ + "Keep-Alive" + ], + "Content-Type": [ + "application/json;charset=UTF-8" + ], + "Date": [ + "Thu, 16 Sep 2021 16:34:55 GMT" + ], + "Keep-Alive": [ + "timeout=5, max=100" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "Apache/2.4" + ], + "Strict-Transport-Security": [ + "max-age=31536000 ; includeSubDomains" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Vary": [ + "User-Agent" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "DENY" + ], + "X-XSS-Protection": [ + "1; mode=block" + ] + }, + "status": { + "code": 200, + "message": "" + }, + "url": "https://hostname.com/SASLogon/oauth/token" + } + } + ], + "recorded_with": "betamax/0.8.1" +} \ No newline at end of file diff --git a/tests/cassettes/tests.integration.test_compute.TestJobDefinitions.test_get_log.json b/tests/cassettes/tests.integration.test_compute.TestJobDefinitions.test_get_log.json new file mode 100644 index 00000000..2380d0fb --- /dev/null +++ b/tests/cassettes/tests.integration.test_compute.TestJobDefinitions.test_get_log.json @@ -0,0 +1,91 @@ +{ + "http_interactions": [ + { + "recorded_at": "2021-09-16T16:34:55", + "request": { + "body": { + "encoding": "utf-8", + "string": "grant_type=password&username=USERNAME&password=*****" + }, + "headers": { + "Accept": [ + "application/json" + ], + "Accept-Encoding": [ + "gzip, deflate" + ], + "Authorization": [ + "Basic [redacted]" + ], + "Connection": [ + "keep-alive" + ], + "Content-Length": [ + "62" + ], + "Content-Type": [ + "application/x-www-form-urlencoded" + ], + "User-Agent": [ + "python-requests/2.22.0" + ] + }, + "method": "POST", + "uri": "https://hostname.com/SASLogon/oauth/token" + }, + "response": { + "body": { + "encoding": "UTF-8", + "string": "{\"access_token\":\"[redacted]\",\"token_type\":\"bearer\",\"id_token\":\"eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vbG9jYWxob3N0L1NBU0xvZ29uL3Rva2VuX2tleXMiLCJraWQiOiJsZWdhY3ktdG9rZW4ta2V5IiwidHlwIjoiSldUIn0.eyJzdWIiOiIyM2I3NDJhOS1jN2IyLTRkNGUtYjBlYy0xZDJhNjdjNjIwOTMiLCJhdWQiOlsic2FzLmVjIl0sImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3QvU0FTTG9nb24vb2F1dGgvdG9rZW4iLCJleHAiOjE2MzE4NDYwOTUsImlhdCI6MTYzMTgxMDA5NSwiYW1yIjpbImV4dCIsInB3ZCJdLCJhenAiOiJzYXMuZWMiLCJzY29wZSI6WyJvcGVuaWQiXSwiZW1haWwiOiJKb25hdGhhbi5XYWxrZXJAc2FzLmNvbSIsInppZCI6InVhYSIsIm9yaWdpbiI6ImxkYXAiLCJqdGkiOiIxZWNjMjA4Yzc1MzQ0ODkxYmZkNjlkYjQ5OWVjZTIzNiIsInByZXZpb3VzX2xvZ29uX3RpbWUiOjE2MzE4MTAwOTUyMzgsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiY2xpZW50X2lkIjoic2FzLmVjIiwiY2lkIjoic2FzLmVjIiwiZ3JhbnRfdHlwZSI6InBhc3N3b3JkIiwidXNlcl9uYW1lIjoiam96d2FsIiwicmV2X3NpZyI6ImUxODA1M2MiLCJhdXRoX3RpbWUiOjE2MzE4MTAwOTUsInVzZXJfaWQiOiIyM2I3NDJhOS1jN2IyLTRkNGUtYjBlYy0xZDJhNjdjNjIwOTMifQ.bsYm7Ubgta0AgJ0lMFNYzfLCpWBKtMEcU1CN-xXNLACBJegZw6kQRKAptg6CQD2WgLr0SMUJHPaWNQwAflK4PlvUGXLuSGMMIi8druScvMtXLWcLyIa0H6Hxggjvl4AQWLru9Txdc-vwLRQh2k5VdTxCuWlZoQIOnEwJubAX7SE_t-8uxPR8ysc1y8SzN3s44-qUbmm-WU8LZYrVRV2DwiE1TU6s_orb6u3AAcLDtuECoOJfF15BqbmtUYzj4les7QvHpp3kza2zL2WJ6NSFaiHlf94bgDhM1CT2PIBZZAiR5-7mrlQuINdPc7j1zwSjo0kq-a3XGZld6F8At39Ofg\",\"expires_in\":35999,\"scope\":\"esvakmcorionterritoryaccess sviusrs SCR viyapython mismakeordertstval CARYEMPS SAS_Visa_TE esvanemeainstructorconsumers harrisindirectreports rdinformoptin esvakmcrenewalforecastconsumers esvakmcorionoppaccess orcoevasrv02 COESRV tksem AWSSandboxAccount01 cloudacadusers modelmanager uaa.resource otggenrnd RNDSIMSUsers openid domainemps1 gelupdates OR_RD_COE scim.read sasvspusers esvakmcriskconsumers SASAdministrators OneDriveUsers openstackusers CASDiscussion scr_us acoe_server_group scr_ci esvarndperftestconsumers esvakmcorionconsultforecastconsumers intcawebcertreq ANALYSIS cooallamer esvakmcorionriskconsumers CTRYUNITEDSTATES tisurvey gtt_users intcausers BLDGR HADOOP-DEV clients.secret esvaallempsconsumers midena SIMSEdit rdtcaccess Safari_list RDAnnounce DSCIENCE unix_r&d TACCDevelopment SAS_TE AWSsalesenableAccount csatechxchange USemps rdanncauto SIMSView Weekly_Wrap defsusers opsglobalorion DomainEmployees AWS-TAM-Call esvanemeaeduconsumers bryanharrisALLemps esvakmcorionriskaccess exnet.simsview KSA_mail_list SSODLPUsers revegyusercommunity uaa.admin clients.admin AMTX esvakmcorionconsumers AMPSX USSAS esvanemeaeduadmins Skypeplugin TSDATASTORUSERS lanpanfilter exnet.simsedit SalesXchange ORE EMINERS sas92_install techoffice COOALLSTAFF sviadms scr_edu rdengineering allamazonusers R&DUS UDSREPORTS clients.read WWMGlobalBanking atlassiangroups aideas hrsb jaredpetersonallreports BLDALL TESSAUSERS KSA_ADGroup birdrace scr_psd R&D-AAD ITatSAS orclus05 scr_og R5TH scr_ga democenterusers HADOOP-L RE_PYTHON clients.write ts-tba-test scim.write ORCLUS08_USERS\",\"jti\":\"1ecc208c75344891bfd69db499ece236\"}" + }, + "headers": { + "Cache-Control": [ + "no-store" + ], + "Connection": [ + "Keep-Alive" + ], + "Content-Type": [ + "application/json;charset=UTF-8" + ], + "Date": [ + "Thu, 16 Sep 2021 16:34:55 GMT" + ], + "Keep-Alive": [ + "timeout=5, max=100" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "Apache/2.4" + ], + "Strict-Transport-Security": [ + "max-age=31536000 ; includeSubDomains" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Vary": [ + "User-Agent" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "DENY" + ], + "X-XSS-Protection": [ + "1; mode=block" + ] + }, + "status": { + "code": 200, + "message": "" + }, + "url": "https://hostname.com/SASLogon/oauth/token" + } + } + ], + "recorded_with": "betamax/0.8.1" +} \ No newline at end of file diff --git a/tests/cassettes/tests.integration.test_compute.TestJobDefinitions.test_get_results.json b/tests/cassettes/tests.integration.test_compute.TestJobDefinitions.test_get_results.json new file mode 100644 index 00000000..9826b31d --- /dev/null +++ b/tests/cassettes/tests.integration.test_compute.TestJobDefinitions.test_get_results.json @@ -0,0 +1,91 @@ +{ + "http_interactions": [ + { + "recorded_at": "2021-09-16T16:34:56", + "request": { + "body": { + "encoding": "utf-8", + "string": "grant_type=password&username=USERNAME&password=*****" + }, + "headers": { + "Accept": [ + "application/json" + ], + "Accept-Encoding": [ + "gzip, deflate" + ], + "Authorization": [ + "Basic [redacted]" + ], + "Connection": [ + "keep-alive" + ], + "Content-Length": [ + "62" + ], + "Content-Type": [ + "application/x-www-form-urlencoded" + ], + "User-Agent": [ + "python-requests/2.22.0" + ] + }, + "method": "POST", + "uri": "https://hostname.com/SASLogon/oauth/token" + }, + "response": { + "body": { + "encoding": "UTF-8", + "string": "{\"access_token\":\"[redacted]\",\"token_type\":\"bearer\",\"id_token\":\"eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vbG9jYWxob3N0L1NBU0xvZ29uL3Rva2VuX2tleXMiLCJraWQiOiJsZWdhY3ktdG9rZW4ta2V5IiwidHlwIjoiSldUIn0.eyJzdWIiOiIyM2I3NDJhOS1jN2IyLTRkNGUtYjBlYy0xZDJhNjdjNjIwOTMiLCJhdWQiOlsic2FzLmVjIl0sImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3QvU0FTTG9nb24vb2F1dGgvdG9rZW4iLCJleHAiOjE2MzE4NDYwOTYsImlhdCI6MTYzMTgxMDA5NiwiYW1yIjpbImV4dCIsInB3ZCJdLCJhenAiOiJzYXMuZWMiLCJzY29wZSI6WyJvcGVuaWQiXSwiZW1haWwiOiJKb25hdGhhbi5XYWxrZXJAc2FzLmNvbSIsInppZCI6InVhYSIsIm9yaWdpbiI6ImxkYXAiLCJqdGkiOiJkMjg5OGE0MTY1YzQ0OWQ5OWM4YWQ5NTljZThiZDFkZSIsInByZXZpb3VzX2xvZ29uX3RpbWUiOjE2MzE4MTAwOTU2MjQsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiY2xpZW50X2lkIjoic2FzLmVjIiwiY2lkIjoic2FzLmVjIiwiZ3JhbnRfdHlwZSI6InBhc3N3b3JkIiwidXNlcl9uYW1lIjoiam96d2FsIiwicmV2X3NpZyI6ImUxODA1M2MiLCJhdXRoX3RpbWUiOjE2MzE4MTAwOTYsInVzZXJfaWQiOiIyM2I3NDJhOS1jN2IyLTRkNGUtYjBlYy0xZDJhNjdjNjIwOTMifQ.VzYlyofJjQF5bbuFmx_gyHnkyLvC4qdbgLQN7_504HiFnd4gSWkA8rv4kJZ6sCz7zcr2RHAP3UvOFmq8em5EiJ_1vHXYBC94VXizOImakQxT4umIuzJBiyeNtRVQQe4lv_ctnMDDspdEw-RpTe5wDb7dfho6RgMYyJ9kmbvJBE6RWBtWo7WnPaM1zoiOasgr9SH81RTB99D8JrcSPwEkn04tgt2Ze3upNhl5OFd0sb00CDxCmixgBdcTv9gzdr0k-W9HVe4vpsZulZ8gPdXAePxacNc1JAXWRP18OL51laCtVb7sLKu0aJJxzdVrbcER-fXPCY1C64dJ3NVh3DG5Mw\",\"expires_in\":35999,\"scope\":\"esvakmcorionterritoryaccess sviusrs SCR viyapython mismakeordertstval CARYEMPS SAS_Visa_TE esvanemeainstructorconsumers harrisindirectreports rdinformoptin esvakmcrenewalforecastconsumers esvakmcorionoppaccess orcoevasrv02 COESRV tksem AWSSandboxAccount01 cloudacadusers modelmanager uaa.resource otggenrnd RNDSIMSUsers openid domainemps1 gelupdates OR_RD_COE scim.read sasvspusers esvakmcriskconsumers SASAdministrators OneDriveUsers openstackusers CASDiscussion scr_us acoe_server_group scr_ci esvarndperftestconsumers esvakmcorionconsultforecastconsumers intcawebcertreq ANALYSIS cooallamer esvakmcorionriskconsumers CTRYUNITEDSTATES tisurvey gtt_users intcausers BLDGR HADOOP-DEV clients.secret esvaallempsconsumers midena SIMSEdit rdtcaccess Safari_list RDAnnounce DSCIENCE unix_r&d TACCDevelopment SAS_TE AWSsalesenableAccount csatechxchange USemps rdanncauto SIMSView Weekly_Wrap defsusers opsglobalorion DomainEmployees AWS-TAM-Call esvanemeaeduconsumers bryanharrisALLemps esvakmcorionriskaccess exnet.simsview KSA_mail_list SSODLPUsers revegyusercommunity uaa.admin clients.admin AMTX esvakmcorionconsumers AMPSX USSAS esvanemeaeduadmins Skypeplugin TSDATASTORUSERS lanpanfilter exnet.simsedit SalesXchange ORE EMINERS sas92_install techoffice COOALLSTAFF sviadms scr_edu rdengineering allamazonusers R&DUS UDSREPORTS clients.read WWMGlobalBanking atlassiangroups aideas hrsb jaredpetersonallreports BLDALL TESSAUSERS KSA_ADGroup birdrace scr_psd R&D-AAD ITatSAS orclus05 scr_og R5TH scr_ga democenterusers HADOOP-L RE_PYTHON clients.write ts-tba-test scim.write ORCLUS08_USERS\",\"jti\":\"d2898a4165c449d99c8ad959ce8bd1de\"}" + }, + "headers": { + "Cache-Control": [ + "no-store" + ], + "Connection": [ + "Keep-Alive" + ], + "Content-Type": [ + "application/json;charset=UTF-8" + ], + "Date": [ + "Thu, 16 Sep 2021 16:34:55 GMT" + ], + "Keep-Alive": [ + "timeout=5, max=100" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "Apache/2.4" + ], + "Strict-Transport-Security": [ + "max-age=31536000 ; includeSubDomains" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Vary": [ + "User-Agent" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "DENY" + ], + "X-XSS-Protection": [ + "1; mode=block" + ] + }, + "status": { + "code": 200, + "message": "" + }, + "url": "https://hostname.com/SASLogon/oauth/token" + } + } + ], + "recorded_with": "betamax/0.8.1" +} \ No newline at end of file diff --git a/tests/cassettes/tests.integration.test_job_definitions.TestJobDefinitions.test_create_definition.json b/tests/cassettes/tests.integration.test_job_definitions.TestJobDefinitions.test_create_definition.json new file mode 100644 index 00000000..2cf11d45 --- /dev/null +++ b/tests/cassettes/tests.integration.test_job_definitions.TestJobDefinitions.test_create_definition.json @@ -0,0 +1,192 @@ +{ + "http_interactions": [ + { + "recorded_at": "2021-09-14T20:49:33", + "request": { + "body": { + "encoding": "utf-8", + "string": "grant_type=password&username=USERNAME&password=*****" + }, + "headers": { + "Accept": [ + "application/json" + ], + "Accept-Encoding": [ + "gzip, deflate" + ], + "Authorization": [ + "Basic [redacted]" + ], + "Connection": [ + "keep-alive" + ], + "Content-Length": [ + "62" + ], + "Content-Type": [ + "application/x-www-form-urlencoded" + ], + "User-Agent": [ + "python-requests/2.22.0" + ] + }, + "method": "POST", + "uri": "https://hostname.com/SASLogon/oauth/token" + }, + "response": { + "body": { + "encoding": "UTF-8", + "string": "{\"access_token\":\"[redacted]\",\"token_type\":\"bearer\",\"id_token\":\"eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vbG9jYWxob3N0L1NBU0xvZ29uL3Rva2VuX2tleXMiLCJraWQiOiJsZWdhY3ktdG9rZW4ta2V5IiwidHlwIjoiSldUIn0.eyJzdWIiOiIyM2I3NDJhOS1jN2IyLTRkNGUtYjBlYy0xZDJhNjdjNjIwOTMiLCJhdWQiOlsic2FzLmVjIl0sImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3QvU0FTTG9nb24vb2F1dGgvdG9rZW4iLCJleHAiOjE2MzE2ODg1NzMsImlhdCI6MTYzMTY1MjU3MywiYW1yIjpbImV4dCIsInB3ZCJdLCJhenAiOiJzYXMuZWMiLCJzY29wZSI6WyJvcGVuaWQiXSwiZW1haWwiOiJKb25hdGhhbi5XYWxrZXJAc2FzLmNvbSIsInppZCI6InVhYSIsIm9yaWdpbiI6ImxkYXAiLCJqdGkiOiJlYzNjYTA0OTAzZTk0YTc4ODI4MjJkNTc4YTExYzJjYiIsInByZXZpb3VzX2xvZ29uX3RpbWUiOjE2MzE2NTI0NDE4MDgsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiY2xpZW50X2lkIjoic2FzLmVjIiwiY2lkIjoic2FzLmVjIiwiZ3JhbnRfdHlwZSI6InBhc3N3b3JkIiwidXNlcl9uYW1lIjoiam96d2FsIiwicmV2X3NpZyI6ImUxODA1M2MiLCJhdXRoX3RpbWUiOjE2MzE2NTI1NzMsInVzZXJfaWQiOiIyM2I3NDJhOS1jN2IyLTRkNGUtYjBlYy0xZDJhNjdjNjIwOTMifQ.b0KeW46rt0nLj62byclH9dNVZmLAhggYXZ3qa1H28qV7M4abWqwM0a1dStAvnTrm-Pn-Q3LmhRHcwN312LUnLsUdvnLl1o_u8C5dEAvivg1VOKCiIw8HQbsmRsEYlhZF60KQyhNDGSJUeu64GSBVHJCVj3i5y0ietqoIEIZnJGz7cbbdo_fzz7dUOduZEGP9mwciRHsJSlE0195GEARqUhPwPmJdDwY72-DeJHORfhO8muIfLjrd7ahVjvHdE2U4xAGiYcJw6gQYuFjT79uTYeQMN7WaP0PpJUAL9wWwggSe1YKqCmV2E8ZsRl3RnCT-yuwHMw_1oAm4ybTxmzRO0Q\",\"expires_in\":35999,\"scope\":\"esvakmcorionterritoryaccess sviusrs SCR viyapython mismakeordertstval CARYEMPS SAS_Visa_TE esvanemeainstructorconsumers harrisindirectreports rdinformoptin esvakmcrenewalforecastconsumers esvakmcorionoppaccess orcoevasrv02 COESRV tksem AWSSandboxAccount01 cloudacadusers modelmanager uaa.resource otggenrnd RNDSIMSUsers openid domainemps1 gelupdates OR_RD_COE scim.read sasvspusers esvakmcriskconsumers SASAdministrators OneDriveUsers openstackusers CASDiscussion scr_us acoe_server_group scr_ci esvarndperftestconsumers esvakmcorionconsultforecastconsumers intcawebcertreq ANALYSIS cooallamer esvakmcorionriskconsumers CTRYUNITEDSTATES tisurvey gtt_users intcausers BLDGR HADOOP-DEV clients.secret esvaallempsconsumers midena SIMSEdit rdtcaccess Safari_list RDAnnounce DSCIENCE unix_r&d TACCDevelopment SAS_TE AWSsalesenableAccount csatechxchange USemps rdanncauto SIMSView Weekly_Wrap defsusers opsglobalorion DomainEmployees AWS-TAM-Call esvanemeaeduconsumers bryanharrisALLemps esvakmcorionriskaccess exnet.simsview KSA_mail_list SSODLPUsers revegyusercommunity uaa.admin clients.admin AMTX esvakmcorionconsumers AMPSX USSAS esvanemeaeduadmins Skypeplugin TSDATASTORUSERS lanpanfilter exnet.simsedit SalesXchange ORE EMINERS sas92_install techoffice COOALLSTAFF sviadms scr_edu rdengineering allamazonusers R&DUS UDSREPORTS clients.read WWMGlobalBanking atlassiangroups aideas hrsb jaredpetersonallreports BLDALL TESSAUSERS KSA_ADGroup birdrace scr_psd R&D-AAD ITatSAS orclus05 scr_og R5TH scr_ga democenterusers HADOOP-L RE_PYTHON clients.write ts-tba-test scim.write ORCLUS08_USERS\",\"jti\":\"ec3ca04903e94a7882822d578a11c2cb\"}" + }, + "headers": { + "Cache-Control": [ + "no-store" + ], + "Connection": [ + "Keep-Alive" + ], + "Content-Type": [ + "application/json;charset=UTF-8" + ], + "Date": [ + "Tue, 14 Sep 2021 20:49:32 GMT" + ], + "Keep-Alive": [ + "timeout=5, max=100" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "Apache/2.4" + ], + "Strict-Transport-Security": [ + "max-age=31536000 ; includeSubDomains" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Vary": [ + "User-Agent" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "DENY" + ], + "X-XSS-Protection": [ + "1; mode=block" + ] + }, + "status": { + "code": 200, + "message": "" + }, + "url": "https://hostname.com/SASLogon/oauth/token" + } + }, + { + "recorded_at": "2021-09-14T20:49:33", + "request": { + "body": { + "encoding": "utf-8", + "string": "{\"version\": 2, \"name\": \"sasctl_test_job\", \"description\": \"Test Job Definition from sasctl\", \"type\": \"Compute\", \"code\": \"proc print data=&TABLE;\", \"parameters\": [{\"version\": 1, \"name\": \"_contextName\", \"type\": \"CHARACTER\", \"label\": \"Context Name\", \"required\": false, \"defaultValue\": \"SAS Studio compute context\"}, {\"version\": 1, \"name\": \"TABLE\", \"type\": \"CHARACTER\", \"label\": \"Table Name\", \"required\": true, \"defaultValue\": null}], \"properties\": []}" + }, + "headers": { + "Accept": [ + "application/vnd.sas.job.definition+json" + ], + "Accept-Encoding": [ + "gzip, deflate" + ], + "Authorization": [ + "Bearer [redacted]" + ], + "Connection": [ + "keep-alive" + ], + "Content-Length": [ + "447" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "python-requests/2.22.0" + ] + }, + "method": "POST", + "uri": "https://hostname.com/jobDefinitions/definitions" + }, + "response": { + "body": { + "encoding": null, + "string": "{\"creationTimeStamp\":\"2021-09-14T20:49:33.350Z\",\"modifiedTimeStamp\":\"2021-09-14T20:49:33.351Z\",\"createdBy\":\"USERNAME\",\"modifiedBy\":\"USERNAME\",\"version\":2,\"id\":\"6e2c5006-d32a-4c85-ae39-b5325e2a1eff\",\"name\":\"sasctl_test_job\",\"description\":\"Test Job Definition from sasctl\",\"type\":\"Compute\",\"parameters\":[{\"version\":1,\"name\":\"_contextName\",\"defaultValue\":\"SAS Studio compute context\",\"type\":\"CHARACTER\",\"label\":\"Context Name\",\"required\":false},{\"version\":1,\"name\":\"TABLE\",\"type\":\"CHARACTER\",\"label\":\"Table Name\",\"required\":true}],\"code\":\"proc print data=&TABLE;\",\"links\":[{\"method\":\"GET\",\"rel\":\"self\",\"href\":\"/jobDefinitions/definitions/6e2c5006-d32a-4c85-ae39-b5325e2a1eff\",\"uri\":\"/jobDefinitions/definitions/6e2c5006-d32a-4c85-ae39-b5325e2a1eff\",\"type\":\"application/vnd.sas.job.definition\"},{\"method\":\"GET\",\"rel\":\"alternate\",\"href\":\"/jobDefinitions/definitions/6e2c5006-d32a-4c85-ae39-b5325e2a1eff\",\"uri\":\"/jobDefinitions/definitions/6e2c5006-d32a-4c85-ae39-b5325e2a1eff\",\"type\":\"application/vnd.sas.summary\"},{\"method\":\"PUT\",\"rel\":\"update\",\"href\":\"/jobDefinitions/definitions/6e2c5006-d32a-4c85-ae39-b5325e2a1eff\",\"uri\":\"/jobDefinitions/definitions/6e2c5006-d32a-4c85-ae39-b5325e2a1eff\",\"type\":\"application/vnd.sas.job.definition\",\"responseType\":\"application/vnd.sas.job.definition\"},{\"method\":\"DELETE\",\"rel\":\"delete\",\"href\":\"/jobDefinitions/definitions/6e2c5006-d32a-4c85-ae39-b5325e2a1eff\",\"uri\":\"/jobDefinitions/definitions/6e2c5006-d32a-4c85-ae39-b5325e2a1eff\"}],\"properties\":[]}" + }, + "headers": { + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Connection": [ + "Keep-Alive" + ], + "Content-Security-Policy": [ + "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' *.sas.com blob: data:; style-src 'self' 'unsafe-inline'; child-src 'self' blob: data: mailto:;" + ], + "Content-Type": [ + "application/vnd.sas.job.definition+json" + ], + "Date": [ + "Tue, 14 Sep 2021 20:49:32 GMT" + ], + "ETag": [ + "\"ktkjtb53\"" + ], + "Expires": [ + "0" + ], + "Keep-Alive": [ + "timeout=5, max=99" + ], + "Last-Modified": [ + "Tue, 14 Sep 2021 20:49:33 GMT" + ], + "Location": [ + "/jobDefinitions/definitions/6e2c5006-d32a-4c85-ae39-b5325e2a1eff" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "Apache/2.4" + ], + "Strict-Transport-Security": [ + "max-age=31536000 ; includeSubDomains" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Vary": [ + "User-Agent" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-XSS-Protection": [ + "1; mode=block" + ] + }, + "status": { + "code": 201, + "message": "" + }, + "url": "https://hostname.com/jobDefinitions/definitions" + } + } + ], + "recorded_with": "betamax/0.8.1" +} \ No newline at end of file diff --git a/tests/cassettes/tests.integration.test_job_definitions.TestJobDefinitions.test_create_definition_bad_param.json b/tests/cassettes/tests.integration.test_job_definitions.TestJobDefinitions.test_create_definition_bad_param.json new file mode 100644 index 00000000..2f1be96e --- /dev/null +++ b/tests/cassettes/tests.integration.test_job_definitions.TestJobDefinitions.test_create_definition_bad_param.json @@ -0,0 +1,91 @@ +{ + "http_interactions": [ + { + "recorded_at": "2021-09-14T21:11:15", + "request": { + "body": { + "encoding": "utf-8", + "string": "grant_type=password&username=USERNAME&password=*****" + }, + "headers": { + "Accept": [ + "application/json" + ], + "Accept-Encoding": [ + "gzip, deflate" + ], + "Authorization": [ + "Basic [redacted]" + ], + "Connection": [ + "keep-alive" + ], + "Content-Length": [ + "62" + ], + "Content-Type": [ + "application/x-www-form-urlencoded" + ], + "User-Agent": [ + "python-requests/2.22.0" + ] + }, + "method": "POST", + "uri": "https://hostname.com/SASLogon/oauth/token" + }, + "response": { + "body": { + "encoding": "UTF-8", + "string": "{\"access_token\":\"[redacted]\",\"token_type\":\"bearer\",\"id_token\":\"eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vbG9jYWxob3N0L1NBU0xvZ29uL3Rva2VuX2tleXMiLCJraWQiOiJsZWdhY3ktdG9rZW4ta2V5IiwidHlwIjoiSldUIn0.eyJzdWIiOiIyM2I3NDJhOS1jN2IyLTRkNGUtYjBlYy0xZDJhNjdjNjIwOTMiLCJhdWQiOlsic2FzLmVjIl0sImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3QvU0FTTG9nb24vb2F1dGgvdG9rZW4iLCJleHAiOjE2MzE2ODk4NzUsImlhdCI6MTYzMTY1Mzg3NSwiYW1yIjpbImV4dCIsInB3ZCJdLCJhenAiOiJzYXMuZWMiLCJzY29wZSI6WyJvcGVuaWQiXSwiZW1haWwiOiJKb25hdGhhbi5XYWxrZXJAc2FzLmNvbSIsInppZCI6InVhYSIsIm9yaWdpbiI6ImxkYXAiLCJqdGkiOiJkOTg3N2I4ZWE3NmM0YzY2YWM0Zjg4N2M2ZjFiZmZmYiIsInByZXZpb3VzX2xvZ29uX3RpbWUiOjE2MzE2NTI1NzMxNTYsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiY2xpZW50X2lkIjoic2FzLmVjIiwiY2lkIjoic2FzLmVjIiwiZ3JhbnRfdHlwZSI6InBhc3N3b3JkIiwidXNlcl9uYW1lIjoiam96d2FsIiwicmV2X3NpZyI6ImUxODA1M2MiLCJhdXRoX3RpbWUiOjE2MzE2NTM4NzUsInVzZXJfaWQiOiIyM2I3NDJhOS1jN2IyLTRkNGUtYjBlYy0xZDJhNjdjNjIwOTMifQ.gdG9fh8zkN9Evabq2MzxgJbHwHvq5-0rTqqxAXLDcnYez9M41KzdDSh883aLHMfeGtmGc4pezEnXWALwkJLFQN3wVucAN06GWG76bKsVgvC8YqZMhdL_xpL__XrnokgN5LO_SIikqmqyTjNDQ1bBZhQONQVKa_2PCxqIXGMn8BO5ErEehCzGb4S06VvOoAcc1_i9yurh4zi_7GZPnuZBSwK242_UdXGw2cqpQ1zg-BD7oi9Jhznp5ThRMFESNhc6igK-uGMN1ATdvnhBJkwH3UdfHIaHspe-az9KgDbSl-GHX0Zu4P1tQSHxwjIfKKubdXX85225VEOE_hzol7SS1A\",\"expires_in\":35999,\"scope\":\"esvakmcorionterritoryaccess sviusrs SCR viyapython mismakeordertstval CARYEMPS SAS_Visa_TE esvanemeainstructorconsumers harrisindirectreports rdinformoptin esvakmcrenewalforecastconsumers esvakmcorionoppaccess orcoevasrv02 COESRV tksem AWSSandboxAccount01 cloudacadusers modelmanager uaa.resource otggenrnd RNDSIMSUsers openid domainemps1 gelupdates OR_RD_COE scim.read sasvspusers esvakmcriskconsumers SASAdministrators OneDriveUsers openstackusers CASDiscussion scr_us acoe_server_group scr_ci esvarndperftestconsumers esvakmcorionconsultforecastconsumers intcawebcertreq ANALYSIS cooallamer esvakmcorionriskconsumers CTRYUNITEDSTATES tisurvey gtt_users intcausers BLDGR HADOOP-DEV clients.secret esvaallempsconsumers midena SIMSEdit rdtcaccess Safari_list RDAnnounce DSCIENCE unix_r&d TACCDevelopment SAS_TE AWSsalesenableAccount csatechxchange USemps rdanncauto SIMSView Weekly_Wrap defsusers opsglobalorion DomainEmployees AWS-TAM-Call esvanemeaeduconsumers bryanharrisALLemps esvakmcorionriskaccess exnet.simsview KSA_mail_list SSODLPUsers revegyusercommunity uaa.admin clients.admin AMTX esvakmcorionconsumers AMPSX USSAS esvanemeaeduadmins Skypeplugin TSDATASTORUSERS lanpanfilter exnet.simsedit SalesXchange ORE EMINERS sas92_install techoffice COOALLSTAFF sviadms scr_edu rdengineering allamazonusers R&DUS UDSREPORTS clients.read WWMGlobalBanking atlassiangroups aideas hrsb jaredpetersonallreports BLDALL TESSAUSERS KSA_ADGroup birdrace scr_psd R&D-AAD ITatSAS orclus05 scr_og R5TH scr_ga democenterusers HADOOP-L RE_PYTHON clients.write ts-tba-test scim.write ORCLUS08_USERS\",\"jti\":\"d9877b8ea76c4c66ac4f887c6f1bfffb\"}" + }, + "headers": { + "Cache-Control": [ + "no-store" + ], + "Connection": [ + "Keep-Alive" + ], + "Content-Type": [ + "application/json;charset=UTF-8" + ], + "Date": [ + "Tue, 14 Sep 2021 21:11:14 GMT" + ], + "Keep-Alive": [ + "timeout=5, max=100" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "Apache/2.4" + ], + "Strict-Transport-Security": [ + "max-age=31536000 ; includeSubDomains" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Vary": [ + "User-Agent" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "DENY" + ], + "X-XSS-Protection": [ + "1; mode=block" + ] + }, + "status": { + "code": 200, + "message": "" + }, + "url": "https://hostname.com/SASLogon/oauth/token" + } + } + ], + "recorded_with": "betamax/0.8.1" +} \ No newline at end of file diff --git a/tests/integration/test_compute.py b/tests/integration/test_compute.py new file mode 100644 index 00000000..fe15996d --- /dev/null +++ b/tests/integration/test_compute.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python +# encoding: utf-8 +# +# Copyright © 2021, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + + +import pytest +from sasctl import RestObj +from sasctl.services import compute + +# Each test will receive a (recorded) Session instance +pytestmark = pytest.mark.usefixtures('session') + + +@pytest.mark.incremental +class TestJobDefinitions: + + def test_create_job(self): + all_contexts = compute.list_contexts() + assert isinstance(all_contexts, list) + assert len(all_contexts) > 0 + + sess = compute.create_session(all_contexts[0]) + assert isinstance(sess, RestObj) + + code = """ + ods html style=HTMLBlue; + proc print data=sashelp.class(OBS=5); + run; + quit; + ods html close; + """ + + params = dict( + name='sasctl test job', + description='Test job execution from sasctl' + ) + job = compute.create_job(sess, code, **params) + assert isinstance(job, RestObj) + assert job.sessionId == sess.id + assert job.state == 'pending' + + def test_get_listing(self): + with pytest.raises(ValueError): + compute.get_listing() + + def test_get_log(self): + with pytest.raises(ValueError): + compute.get_log() + + def test_get_results(self): + with pytest.raises(ValueError): + compute.get_results() + + + diff --git a/tests/integration/test_job_definitions.py b/tests/integration/test_job_definitions.py new file mode 100644 index 00000000..73a92891 --- /dev/null +++ b/tests/integration/test_job_definitions.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# encoding: utf-8 +# +# Copyright © 2019, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + + +from unittest import mock + +import pytest +from sasctl import RestObj +from sasctl.services import job_definitions + +# Each test will receive a (recorded) Session instance +pytestmark = pytest.mark.usefixtures('session') + + +@pytest.mark.incremental +class TestJobDefinitions: + def test_create_definition(self): + + params = dict( + name='sasctl_test_job', + description='Test Job Definition from sasctl', + type_='Compute', + code='proc print data=&TABLE;', + parameters=[ + dict(name='_contextName', + defaultValue='SAS Studio compute context', + type='character', + label='Context Name'), + dict(name='TABLE', + type='character', + label='Table Name', + required=True) + ] + ) + definition = job_definitions.create_definition(**params) + + assert isinstance(definition, RestObj) + assert definition['name'] == params['name'] + assert definition['description'] == params['description'] + + def test_create_definition_bad_param(self): + params = dict( + name='sasctl_test_job', + type_='Compute', + code='proc print data=&TABLE;', + parameters=[ + dict(name='TABLE', + type='decimal', + label='Table Name', + required=True) + ] + ) + + with pytest.raises(ValueError) as e: + job_definitions.create_definition(**params) + + assert "'DECIMAL'" in str(e.value)