mirror of
https://github.com/sasjs/adapter.git
synced 2026-01-17 17:10:05 +00:00
wip(context): created ContextManager
This commit is contained in:
1339
package-lock.json
generated
1339
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -57,6 +57,7 @@
|
|||||||
},
|
},
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@sasjs/utils": "^1.3.0",
|
||||||
"es6-promise": "^4.2.8",
|
"es6-promise": "^4.2.8",
|
||||||
"form-data": "^3.0.0",
|
"form-data": "^3.0.0",
|
||||||
"isomorphic-fetch": "^2.2.1"
|
"isomorphic-fetch": "^2.2.1"
|
||||||
|
|||||||
462
src/ContextManager.ts
Normal file
462
src/ContextManager.ts
Normal file
@@ -0,0 +1,462 @@
|
|||||||
|
import {
|
||||||
|
Context,
|
||||||
|
CsrfToken,
|
||||||
|
EditContextInput,
|
||||||
|
ContextAllAttributes
|
||||||
|
} from './types'
|
||||||
|
import { makeRequest, isUrl } from './utils'
|
||||||
|
import { SASViyaApiClient } from './SASViyaApiClient'
|
||||||
|
import { prefixMessage } from '@sasjs/utils/error'
|
||||||
|
|
||||||
|
export class ContextManager {
|
||||||
|
private sasViyaApiClient: SASViyaApiClient | null = null
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private serverUrl: string,
|
||||||
|
private setCsrfToken: (csrfToken: CsrfToken) => void
|
||||||
|
) {
|
||||||
|
if (serverUrl) isUrl(serverUrl) // ?
|
||||||
|
}
|
||||||
|
|
||||||
|
private csrfToken: CsrfToken | null = null
|
||||||
|
|
||||||
|
public async getComputeContexts(accessToken?: string) {
|
||||||
|
const headers: any = {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accessToken) {
|
||||||
|
headers.Authorization = `Bearer ${accessToken}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const { result: contexts } = await this.request<{ items: Context[] }>(
|
||||||
|
`${this.serverUrl}/compute/contexts?limit=10000`,
|
||||||
|
{ headers }
|
||||||
|
).catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while getting compute contexts. ')
|
||||||
|
})
|
||||||
|
|
||||||
|
const contextsList = contexts && contexts.items ? contexts.items : []
|
||||||
|
|
||||||
|
return contextsList.map((context: any) => ({
|
||||||
|
createdBy: context.createdBy,
|
||||||
|
id: context.id,
|
||||||
|
name: context.name,
|
||||||
|
version: context.version,
|
||||||
|
attributes: {}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getLauncherContexts(accessToken?: string) {
|
||||||
|
const headers: any = {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accessToken) {
|
||||||
|
headers.Authorization = `Bearer ${accessToken}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const { result: contexts } = await this.request<{ items: Context[] }>(
|
||||||
|
`${this.serverUrl}/launcher/contexts?limit=10000`,
|
||||||
|
{ headers }
|
||||||
|
).catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while getting launcher contexts. ')
|
||||||
|
})
|
||||||
|
|
||||||
|
const contextsList = contexts && contexts.items ? contexts.items : []
|
||||||
|
|
||||||
|
return contextsList.map((context: any) => ({
|
||||||
|
createdBy: context.createdBy,
|
||||||
|
id: context.id,
|
||||||
|
name: context.name,
|
||||||
|
version: context.version,
|
||||||
|
attributes: {}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Check if context already exist, reject with the error if so
|
||||||
|
public async createComputeContext(
|
||||||
|
contextName: string,
|
||||||
|
launchContextName: string,
|
||||||
|
sharedAccountId: string,
|
||||||
|
autoExecLines: string[],
|
||||||
|
accessToken?: string,
|
||||||
|
authorizedUsers?: string[]
|
||||||
|
) {
|
||||||
|
if (!contextName) {
|
||||||
|
throw new Error('Context name is required.')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (launchContextName) {
|
||||||
|
const launcherContexts = await this.getLauncherContexts(accessToken)
|
||||||
|
|
||||||
|
if (
|
||||||
|
!launcherContexts.find((context) => context.name === launchContextName)
|
||||||
|
) {
|
||||||
|
const description = `The launcher context for ${launchContextName}`
|
||||||
|
const launchType = 'direct'
|
||||||
|
|
||||||
|
const newLauncherContext = await this.createLauncherContext(
|
||||||
|
launchContextName,
|
||||||
|
description,
|
||||||
|
launchType,
|
||||||
|
accessToken
|
||||||
|
).catch((err) => {
|
||||||
|
throw new Error(`Error while creating launcher context. ${err}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (newLauncherContext && newLauncherContext.name) {
|
||||||
|
launchContextName = newLauncherContext.name
|
||||||
|
} else {
|
||||||
|
throw new Error('Error while creating launcher context.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers: any = {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accessToken) {
|
||||||
|
headers.Authorization = `Bearer ${accessToken}`
|
||||||
|
}
|
||||||
|
|
||||||
|
let attributes = { reuseServerProcesses: true } as object
|
||||||
|
|
||||||
|
if (sharedAccountId)
|
||||||
|
attributes = { ...attributes, runServerAs: sharedAccountId }
|
||||||
|
|
||||||
|
const requestBody: any = {
|
||||||
|
name: contextName,
|
||||||
|
launchContext: {
|
||||||
|
contextName: launchContextName || ''
|
||||||
|
},
|
||||||
|
attributes
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authorizedUsers && authorizedUsers.length) {
|
||||||
|
requestBody['authorizedUsers'] = authorizedUsers
|
||||||
|
} else {
|
||||||
|
requestBody['authorizeAllAuthenticatedUsers'] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (autoExecLines) {
|
||||||
|
requestBody.environment = { autoExecLines }
|
||||||
|
}
|
||||||
|
|
||||||
|
const createContextRequest: RequestInit = {
|
||||||
|
method: 'POST',
|
||||||
|
headers,
|
||||||
|
body: JSON.stringify(requestBody)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { result: context } = await this.request<Context>(
|
||||||
|
`${this.serverUrl}/compute/contexts`,
|
||||||
|
createContextRequest
|
||||||
|
).catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while creating compute context. ')
|
||||||
|
})
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Check if context already exist, reject with the error if so
|
||||||
|
public async createLauncherContext(
|
||||||
|
contextName: string,
|
||||||
|
description: string,
|
||||||
|
launchType = 'direct',
|
||||||
|
accessToken?: string
|
||||||
|
) {
|
||||||
|
if (!contextName) {
|
||||||
|
throw new Error('Context name is required.')
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers: any = {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accessToken) {
|
||||||
|
headers.Authorization = `Bearer ${accessToken}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestBody: any = {
|
||||||
|
name: contextName,
|
||||||
|
description: description,
|
||||||
|
launchType
|
||||||
|
}
|
||||||
|
|
||||||
|
const createContextRequest: RequestInit = {
|
||||||
|
method: 'POST',
|
||||||
|
headers,
|
||||||
|
body: JSON.stringify(requestBody)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { result: context } = await this.request<Context>(
|
||||||
|
`${this.serverUrl}/launcher/contexts`,
|
||||||
|
createContextRequest
|
||||||
|
).catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while creating launcher context. ')
|
||||||
|
})
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Check if trying to edit one of default SAS contexts, reject with the error if so
|
||||||
|
// TODO: rename to editComputeContext
|
||||||
|
public async editContext(
|
||||||
|
contextName: string,
|
||||||
|
editedContext: EditContextInput,
|
||||||
|
accessToken?: string
|
||||||
|
) {
|
||||||
|
if (!contextName) {
|
||||||
|
throw new Error('Invalid context name.')
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers: any = {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accessToken) {
|
||||||
|
headers.Authorization = `Bearer ${accessToken}`
|
||||||
|
}
|
||||||
|
|
||||||
|
let originalContext
|
||||||
|
|
||||||
|
originalContext = await this.getComputeContextByName(
|
||||||
|
contextName,
|
||||||
|
accessToken
|
||||||
|
)
|
||||||
|
|
||||||
|
// Try to find context by id, when context name has been changed.
|
||||||
|
if (!originalContext) {
|
||||||
|
originalContext = await this.getComputeContextById(
|
||||||
|
editedContext.id!,
|
||||||
|
accessToken
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { result: context, etag } = await this.request<Context>(
|
||||||
|
`${this.serverUrl}/compute/contexts/${originalContext.id}`,
|
||||||
|
{
|
||||||
|
headers
|
||||||
|
}
|
||||||
|
).catch((err) => {
|
||||||
|
if (err && err.status === 404) {
|
||||||
|
throw new Error(
|
||||||
|
`The context '${contextName}' was not found on this server.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
throw err
|
||||||
|
})
|
||||||
|
|
||||||
|
// An If-Match header with the value of the last ETag for the context
|
||||||
|
// is required to be able to update it
|
||||||
|
// https://developer.sas.com/apis/rest/Compute/#update-a-context-definition
|
||||||
|
headers['If-Match'] = etag
|
||||||
|
|
||||||
|
const updateContextRequest: RequestInit = {
|
||||||
|
method: 'PUT',
|
||||||
|
headers,
|
||||||
|
body: JSON.stringify({
|
||||||
|
...context,
|
||||||
|
...editedContext,
|
||||||
|
attributes: { ...context.attributes, ...editedContext.attributes }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return await this.request<Context>(
|
||||||
|
`${this.serverUrl}/compute/contexts/${context.id}`,
|
||||||
|
updateContextRequest
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getComputeContextByName(
|
||||||
|
contextName: string,
|
||||||
|
accessToken?: string
|
||||||
|
): Promise<Context> {
|
||||||
|
const headers: any = {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accessToken) {
|
||||||
|
headers.Authorization = `Bearer ${accessToken}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const { result: contexts } = await this.request<{ items: Context[] }>(
|
||||||
|
`${this.serverUrl}/compute/contexts?filter=eq(name, "${contextName}")`,
|
||||||
|
{ headers }
|
||||||
|
).catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while getting compute context by name. ')
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!contexts || !(contexts.items && contexts.items.length)) {
|
||||||
|
throw new Error(
|
||||||
|
`The context '${contextName}' was not found at '${this.serverUrl}'.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return contexts.items[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getComputeContextById(
|
||||||
|
contextId: string,
|
||||||
|
accessToken?: string
|
||||||
|
): Promise<ContextAllAttributes> {
|
||||||
|
const headers: any = {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accessToken) {
|
||||||
|
headers.Authorization = `Bearer ${accessToken}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const { result: context } = await this.request<ContextAllAttributes>(
|
||||||
|
`${this.serverUrl}/compute/contexts/${contextId}`,
|
||||||
|
{ headers }
|
||||||
|
).catch((err) => {
|
||||||
|
throw prefixMessage(err, 'Error while getting compute context by id. ')
|
||||||
|
})
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getExecutableContexts(
|
||||||
|
executeScript: Function,
|
||||||
|
accessToken?: string
|
||||||
|
) {
|
||||||
|
console.log(`[324]`, 324)
|
||||||
|
const headers: any = {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accessToken) {
|
||||||
|
headers.Authorization = `Bearer ${accessToken}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const { result: contexts } = await this.request<{ items: Context[] }>(
|
||||||
|
`${this.serverUrl}/compute/contexts?limit=10000`,
|
||||||
|
{ headers }
|
||||||
|
).catch((err) => {
|
||||||
|
throw err // fixme
|
||||||
|
})
|
||||||
|
|
||||||
|
const contextsList = contexts.items || []
|
||||||
|
const executableContexts: any[] = []
|
||||||
|
|
||||||
|
console.log(`[this.sasViyaApiClient]`, this.sasViyaApiClient)
|
||||||
|
|
||||||
|
const promises = contextsList.map((context: any) => {
|
||||||
|
const linesOfCode = ['%put &=sysuserid;']
|
||||||
|
|
||||||
|
return () =>
|
||||||
|
this.sasViyaApiClient!.executeScript(
|
||||||
|
`test-${context.name}`,
|
||||||
|
linesOfCode,
|
||||||
|
context.name,
|
||||||
|
accessToken,
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
).catch((err: any) => err)
|
||||||
|
})
|
||||||
|
|
||||||
|
let results: any[] = []
|
||||||
|
|
||||||
|
for (const promise of promises) results.push(await promise())
|
||||||
|
|
||||||
|
console.log(`[results]`, results)
|
||||||
|
|
||||||
|
results.forEach((result: any, index: number) => {
|
||||||
|
if (result && result.log) {
|
||||||
|
try {
|
||||||
|
const resultParsed = result.log
|
||||||
|
let sysUserId = ''
|
||||||
|
|
||||||
|
const sysUserIdLog = resultParsed
|
||||||
|
.split('\n')
|
||||||
|
.find((line: string) => line.startsWith('SYSUSERID='))
|
||||||
|
|
||||||
|
if (sysUserIdLog) {
|
||||||
|
sysUserId = sysUserIdLog.replace('SYSUSERID=', '')
|
||||||
|
|
||||||
|
executableContexts.push({
|
||||||
|
createdBy: contextsList[index].createdBy,
|
||||||
|
id: contextsList[index].id,
|
||||||
|
name: contextsList[index].name,
|
||||||
|
version: contextsList[index].version,
|
||||||
|
attributes: {
|
||||||
|
sysUserId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return executableContexts
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Check if trying to delete one of default SAS contexts, reject with the error if so
|
||||||
|
// TODO: rename to deleteComputeContext
|
||||||
|
public async deleteContext(contextName: string, accessToken?: string) {
|
||||||
|
if (!contextName) {
|
||||||
|
throw new Error('Invalid context name.')
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers: any = {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accessToken) {
|
||||||
|
headers.Authorization = `Bearer ${accessToken}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const context = await this.getComputeContextByName(contextName, accessToken)
|
||||||
|
|
||||||
|
const deleteContextRequest: RequestInit = {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers
|
||||||
|
}
|
||||||
|
|
||||||
|
return await this.request<Context>(
|
||||||
|
`${this.serverUrl}/compute/contexts/${context.id}`,
|
||||||
|
deleteContextRequest
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: implement editLauncherContext method
|
||||||
|
|
||||||
|
// TODO: implement deleteLauncherContext method
|
||||||
|
|
||||||
|
private async request<T>(
|
||||||
|
url: string,
|
||||||
|
options: RequestInit,
|
||||||
|
contentType: 'text' | 'json' = 'json'
|
||||||
|
) {
|
||||||
|
if (this.csrfToken) {
|
||||||
|
options.headers = {
|
||||||
|
...options.headers,
|
||||||
|
[this.csrfToken.headerName]: this.csrfToken.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return await makeRequest<T>(
|
||||||
|
url,
|
||||||
|
options,
|
||||||
|
(token) => {
|
||||||
|
this.csrfToken = token
|
||||||
|
this.setCsrfToken(token)
|
||||||
|
},
|
||||||
|
contentType
|
||||||
|
).catch((err) => {
|
||||||
|
throw prefixMessage(
|
||||||
|
err,
|
||||||
|
'Error while making request in Context Manager. '
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ import {
|
|||||||
} from './types'
|
} from './types'
|
||||||
import { formatDataForRequest } from './utils/formatDataForRequest'
|
import { formatDataForRequest } from './utils/formatDataForRequest'
|
||||||
import { SessionManager } from './SessionManager'
|
import { SessionManager } from './SessionManager'
|
||||||
|
import { ContextManager } from './ContextManager'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A client for interfacing with the SAS Viya REST API.
|
* A client for interfacing with the SAS Viya REST API.
|
||||||
@@ -45,6 +46,7 @@ export class SASViyaApiClient {
|
|||||||
this.contextName,
|
this.contextName,
|
||||||
this.setCsrfToken
|
this.setCsrfToken
|
||||||
)
|
)
|
||||||
|
private contextManager = new ContextManager(this.serverUrl, this.setCsrfToken)
|
||||||
private folderMap = new Map<string, Job[]>()
|
private folderMap = new Map<string, Job[]>()
|
||||||
|
|
||||||
public get debug() {
|
public get debug() {
|
||||||
@@ -98,28 +100,7 @@ export class SASViyaApiClient {
|
|||||||
* @param accessToken - an access token for an authorized user.
|
* @param accessToken - an access token for an authorized user.
|
||||||
*/
|
*/
|
||||||
public async getComputeContexts(accessToken?: string) {
|
public async getComputeContexts(accessToken?: string) {
|
||||||
const headers: any = {
|
return await this.contextManager.getComputeContexts(accessToken)
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accessToken) {
|
|
||||||
headers.Authorization = `Bearer ${accessToken}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const { result: contexts } = await this.request<{ items: Context[] }>(
|
|
||||||
`${this.serverUrl}/compute/contexts?limit=10000`,
|
|
||||||
{ headers }
|
|
||||||
)
|
|
||||||
|
|
||||||
const contextsList = contexts && contexts.items ? contexts.items : []
|
|
||||||
|
|
||||||
return contextsList.map((context: any) => ({
|
|
||||||
createdBy: context.createdBy,
|
|
||||||
id: context.id,
|
|
||||||
name: context.name,
|
|
||||||
version: context.version,
|
|
||||||
attributes: {}
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -127,28 +108,7 @@ export class SASViyaApiClient {
|
|||||||
* @param accessToken - an access token for an authorized user.
|
* @param accessToken - an access token for an authorized user.
|
||||||
*/
|
*/
|
||||||
public async getLauncherContexts(accessToken?: string) {
|
public async getLauncherContexts(accessToken?: string) {
|
||||||
const headers: any = {
|
return await this.contextManager.getLauncherContexts(accessToken)
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accessToken) {
|
|
||||||
headers.Authorization = `Bearer ${accessToken}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const { result: contexts } = await this.request<{ items: Context[] }>(
|
|
||||||
`${this.serverUrl}/launcher/contexts?limit=10000`,
|
|
||||||
{ headers }
|
|
||||||
)
|
|
||||||
|
|
||||||
const contextsList = contexts && contexts.items ? contexts.items : []
|
|
||||||
|
|
||||||
return contextsList.map((context: any) => ({
|
|
||||||
createdBy: context.createdBy,
|
|
||||||
id: context.id,
|
|
||||||
name: context.name,
|
|
||||||
version: context.version,
|
|
||||||
attributes: {}
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -156,74 +116,10 @@ export class SASViyaApiClient {
|
|||||||
* @param accessToken - an access token for an authorized user.
|
* @param accessToken - an access token for an authorized user.
|
||||||
*/
|
*/
|
||||||
public async getExecutableContexts(accessToken?: string) {
|
public async getExecutableContexts(accessToken?: string) {
|
||||||
const headers: any = {
|
return await this.contextManager.getExecutableContexts(
|
||||||
'Content-Type': 'application/json'
|
this.executeScript,
|
||||||
}
|
accessToken
|
||||||
|
)
|
||||||
if (accessToken) {
|
|
||||||
headers.Authorization = `Bearer ${accessToken}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const { result: contexts } = await this.request<{ items: Context[] }>(
|
|
||||||
`${this.serverUrl}/compute/contexts?limit=10000`,
|
|
||||||
{ headers }
|
|
||||||
).catch((err) => {
|
|
||||||
throw err
|
|
||||||
})
|
|
||||||
|
|
||||||
const contextsList = contexts.items || []
|
|
||||||
const executableContexts: any[] = []
|
|
||||||
|
|
||||||
const promises = contextsList.map((context: any) => {
|
|
||||||
const linesOfCode = ['%put &=sysuserid;']
|
|
||||||
|
|
||||||
return () =>
|
|
||||||
this.executeScript(
|
|
||||||
`test-${context.name}`,
|
|
||||||
linesOfCode,
|
|
||||||
context.name,
|
|
||||||
accessToken,
|
|
||||||
null,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
true
|
|
||||||
).catch((err) => err)
|
|
||||||
})
|
|
||||||
|
|
||||||
let results: any[] = []
|
|
||||||
|
|
||||||
for (const promise of promises) results.push(await promise())
|
|
||||||
|
|
||||||
results.forEach((result: any, index: number) => {
|
|
||||||
if (result && result.log) {
|
|
||||||
try {
|
|
||||||
const resultParsed = result.log
|
|
||||||
let sysUserId = ''
|
|
||||||
|
|
||||||
const sysUserIdLog = resultParsed
|
|
||||||
.split('\n')
|
|
||||||
.find((line: string) => line.startsWith('SYSUSERID='))
|
|
||||||
|
|
||||||
if (sysUserIdLog) {
|
|
||||||
sysUserId = sysUserIdLog.replace('SYSUSERID=', '')
|
|
||||||
|
|
||||||
executableContexts.push({
|
|
||||||
createdBy: contextsList[index].createdBy,
|
|
||||||
id: contextsList[index].id,
|
|
||||||
name: contextsList[index].name,
|
|
||||||
version: contextsList[index].version,
|
|
||||||
attributes: {
|
|
||||||
sysUserId
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return executableContexts
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -284,79 +180,14 @@ export class SASViyaApiClient {
|
|||||||
accessToken?: string,
|
accessToken?: string,
|
||||||
authorizedUsers?: string[]
|
authorizedUsers?: string[]
|
||||||
) {
|
) {
|
||||||
if (!contextName) {
|
return await this.contextManager.createComputeContext(
|
||||||
throw new Error('Context name is required.')
|
contextName,
|
||||||
}
|
launchContextName,
|
||||||
|
sharedAccountId,
|
||||||
if (launchContextName) {
|
autoExecLines,
|
||||||
const launcherContexts = await this.getLauncherContexts(accessToken)
|
accessToken,
|
||||||
|
authorizedUsers
|
||||||
if (
|
|
||||||
!launcherContexts.find((context) => context.name === launchContextName)
|
|
||||||
) {
|
|
||||||
const description = `The launcher context for ${launchContextName}`
|
|
||||||
const launchType = 'direct'
|
|
||||||
|
|
||||||
const newLauncherContext = await this.createLauncherContext(
|
|
||||||
launchContextName,
|
|
||||||
description,
|
|
||||||
launchType,
|
|
||||||
accessToken
|
|
||||||
).catch((err) => {
|
|
||||||
throw new Error(`Error while creating launcher context. ${err}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
if (newLauncherContext && newLauncherContext.name) {
|
|
||||||
launchContextName = newLauncherContext.name
|
|
||||||
} else {
|
|
||||||
throw new Error('Error while creating launcher context.')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const headers: any = {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accessToken) {
|
|
||||||
headers.Authorization = `Bearer ${accessToken}`
|
|
||||||
}
|
|
||||||
|
|
||||||
let attributes = { reuseServerProcesses: true } as object
|
|
||||||
|
|
||||||
if (sharedAccountId)
|
|
||||||
attributes = { ...attributes, runServerAs: sharedAccountId }
|
|
||||||
|
|
||||||
const requestBody: any = {
|
|
||||||
name: contextName,
|
|
||||||
launchContext: {
|
|
||||||
contextName: launchContextName || ''
|
|
||||||
},
|
|
||||||
attributes
|
|
||||||
}
|
|
||||||
|
|
||||||
if (authorizedUsers && authorizedUsers.length) {
|
|
||||||
requestBody['authorizedUsers'] = authorizedUsers
|
|
||||||
} else {
|
|
||||||
requestBody['authorizeAllAuthenticatedUsers'] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (autoExecLines) {
|
|
||||||
requestBody.environment = { autoExecLines }
|
|
||||||
}
|
|
||||||
|
|
||||||
const createContextRequest: RequestInit = {
|
|
||||||
method: 'POST',
|
|
||||||
headers,
|
|
||||||
body: JSON.stringify(requestBody)
|
|
||||||
}
|
|
||||||
|
|
||||||
const { result: context } = await this.request<Context>(
|
|
||||||
`${this.serverUrl}/compute/contexts`,
|
|
||||||
createContextRequest
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return context
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -372,36 +203,12 @@ export class SASViyaApiClient {
|
|||||||
launchType = 'direct',
|
launchType = 'direct',
|
||||||
accessToken?: string
|
accessToken?: string
|
||||||
) {
|
) {
|
||||||
if (!contextName) {
|
return await this.contextManager.createLauncherContext(
|
||||||
throw new Error('Context name is required.')
|
contextName,
|
||||||
}
|
description,
|
||||||
|
launchType,
|
||||||
const headers: any = {
|
accessToken
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accessToken) {
|
|
||||||
headers.Authorization = `Bearer ${accessToken}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const requestBody: any = {
|
|
||||||
name: contextName,
|
|
||||||
description: description,
|
|
||||||
launchType
|
|
||||||
}
|
|
||||||
|
|
||||||
const createContextRequest: RequestInit = {
|
|
||||||
method: 'POST',
|
|
||||||
headers,
|
|
||||||
body: JSON.stringify(requestBody)
|
|
||||||
}
|
|
||||||
|
|
||||||
const { result: context } = await this.request<Context>(
|
|
||||||
`${this.serverUrl}/launcher/contexts`,
|
|
||||||
createContextRequest
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return context
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -415,70 +222,10 @@ export class SASViyaApiClient {
|
|||||||
editedContext: EditContextInput,
|
editedContext: EditContextInput,
|
||||||
accessToken?: string
|
accessToken?: string
|
||||||
) {
|
) {
|
||||||
if (!contextName) {
|
return await this.contextManager.editContext(
|
||||||
throw new Error('Invalid context name.')
|
|
||||||
}
|
|
||||||
|
|
||||||
const headers: any = {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accessToken) {
|
|
||||||
headers.Authorization = `Bearer ${accessToken}`
|
|
||||||
}
|
|
||||||
|
|
||||||
let originalContext
|
|
||||||
|
|
||||||
originalContext = await this.getComputeContextByName(
|
|
||||||
contextName,
|
contextName,
|
||||||
|
editedContext,
|
||||||
accessToken
|
accessToken
|
||||||
).catch((err) => {
|
|
||||||
throw err
|
|
||||||
})
|
|
||||||
|
|
||||||
// Try to find context by id, when context name has been changed.
|
|
||||||
if (!originalContext) {
|
|
||||||
originalContext = await this.getComputeContextById(
|
|
||||||
editedContext.id!,
|
|
||||||
accessToken
|
|
||||||
).catch((err) => {
|
|
||||||
throw err
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const { result: context, etag } = await this.request<Context>(
|
|
||||||
`${this.serverUrl}/compute/contexts/${originalContext.id}`,
|
|
||||||
{
|
|
||||||
headers
|
|
||||||
}
|
|
||||||
).catch((err) => {
|
|
||||||
if (err && err.status === 404) {
|
|
||||||
throw new Error(
|
|
||||||
`The context '${contextName}' was not found on this server.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
throw err
|
|
||||||
})
|
|
||||||
|
|
||||||
// An If-Match header with the value of the last ETag for the context
|
|
||||||
// is required to be able to update it
|
|
||||||
// https://developer.sas.com/apis/rest/Compute/#update-a-context-definition
|
|
||||||
headers['If-Match'] = etag
|
|
||||||
|
|
||||||
const updateContextRequest: RequestInit = {
|
|
||||||
method: 'PUT',
|
|
||||||
headers,
|
|
||||||
body: JSON.stringify({
|
|
||||||
...context,
|
|
||||||
...editedContext,
|
|
||||||
attributes: { ...context.attributes, ...editedContext.attributes }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.request<Context>(
|
|
||||||
`${this.serverUrl}/compute/contexts/${context.id}`,
|
|
||||||
updateContextRequest
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -488,29 +235,7 @@ export class SASViyaApiClient {
|
|||||||
* @param accessToken - an access token for an authorized user.
|
* @param accessToken - an access token for an authorized user.
|
||||||
*/
|
*/
|
||||||
public async deleteContext(contextName: string, accessToken?: string) {
|
public async deleteContext(contextName: string, accessToken?: string) {
|
||||||
if (!contextName) {
|
return await this.contextManager.deleteContext(contextName, accessToken)
|
||||||
throw new Error('Invalid context name.')
|
|
||||||
}
|
|
||||||
|
|
||||||
const headers: any = {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accessToken) {
|
|
||||||
headers.Authorization = `Bearer ${accessToken}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const context = await this.getComputeContextByName(contextName, accessToken)
|
|
||||||
|
|
||||||
const deleteContextRequest: RequestInit = {
|
|
||||||
method: 'DELETE',
|
|
||||||
headers
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.request<Context>(
|
|
||||||
`${this.serverUrl}/compute/contexts/${context.id}`,
|
|
||||||
deleteContextRequest
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1504,26 +1229,10 @@ export class SASViyaApiClient {
|
|||||||
contextName: string,
|
contextName: string,
|
||||||
accessToken?: string
|
accessToken?: string
|
||||||
): Promise<Context> {
|
): Promise<Context> {
|
||||||
const headers: any = {
|
return await this.contextManager.getComputeContextByName(
|
||||||
'Content-Type': 'application/json'
|
contextName,
|
||||||
}
|
accessToken
|
||||||
|
|
||||||
if (accessToken) {
|
|
||||||
headers.Authorization = `Bearer ${accessToken}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const { result: contexts } = await this.request<{ items: Context[] }>(
|
|
||||||
`${this.serverUrl}/compute/contexts?filter=eq(name, "${contextName}")`,
|
|
||||||
{ headers }
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!contexts || !(contexts.items && contexts.items.length)) {
|
|
||||||
throw new Error(
|
|
||||||
`The context '${contextName}' was not found at '${this.serverUrl}'.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return contexts.items[0]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1535,22 +1244,10 @@ export class SASViyaApiClient {
|
|||||||
contextId: string,
|
contextId: string,
|
||||||
accessToken?: string
|
accessToken?: string
|
||||||
): Promise<ContextAllAttributes> {
|
): Promise<ContextAllAttributes> {
|
||||||
const headers: any = {
|
return await this.contextManager.getComputeContextById(
|
||||||
'Content-Type': 'application/json'
|
contextId,
|
||||||
}
|
accessToken
|
||||||
|
)
|
||||||
if (accessToken) {
|
|
||||||
headers.Authorization = `Bearer ${accessToken}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const { result: context } = await this.request<ContextAllAttributes>(
|
|
||||||
`${this.serverUrl}/compute/contexts/${contextId}`,
|
|
||||||
{ headers }
|
|
||||||
).catch((err) => {
|
|
||||||
throw err
|
|
||||||
})
|
|
||||||
|
|
||||||
return context
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user