Skip to content

Commit

Permalink
fix: use exec status to exit from polling and code cleanup
Browse files Browse the repository at this point in the history
Signed-off-by: Lenin Mehedy <lenin.mehedy@swirldslabs.com>
  • Loading branch information
leninmehedy committed Jan 15, 2024
1 parent 7e03a6e commit fc26a01
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 83 deletions.
166 changes: 85 additions & 81 deletions fullstack-network-manager/src/core/kubectl2.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -245,35 +245,6 @@ export class Kubectl2 {
return contexts
}

parseLsOutput (output) {
if (!output) return []

const items = []
const lines = output.split('\n')
for (let line of lines) {
line = line.replace(/\s+/g, '|')
const parts = line.split('|')
if (parts.length === 9) {
const name = parts[parts.length - 1]
if (name !== '.' && name !== '..') {
const permission = parts[0]
const item = {
directory: permission[0] === 'd',
owner: parts[2],
group: parts[3],
size: parts[4],
modifiedAt: `${parts[5]} ${parts[6]} ${parts[7]}`,
name
}

items.push(item)
}
}
}

return items
}

/**
* List files and directories in a container
*
Expand All @@ -296,52 +267,36 @@ export class Kubectl2 {
*/
async listDir (podName, containerName, destPath, timeout = 5000) {
try {
// verify that file is copied correctly
const self = this
const execInstance = new k8s.Exec(this._kubeConfig)
const command = ['ls', '-la', destPath]
const writerStream = new sb.WritableStreamBuffer()
const errStream = new sb.WritableStreamBuffer()

let output = ''
await execInstance.exec(
this.getCurrentNamespace(),
podName,
containerName,
command,
writerStream,
errStream,
null,
false,
({ status }) => {
if (status === 'Failure' || errStream.size()) {
throw new FullstackTestingError(`Error - details: \n ${errStream.getContentsAsString()}`)
const output = await this.getExecOutput(podName, containerName, ['ls', '-la', destPath])
if (!output) return []

// parse the output and return the entries
const items = []
const lines = output.split('\n')
for (let line of lines) {
line = line.replace(/\s+/g, '|')
const parts = line.split('|')
if (parts.length === 9) {
const name = parts[parts.length - 1]
if (name !== '.' && name !== '..') {
const permission = parts[0]
const item = {
directory: permission[0] === 'd',
owner: parts[2],
group: parts[3],
size: parts[4],
modifiedAt: `${parts[5]} ${parts[6]} ${parts[7]}`,
name
}

items.push(item)
}

output = writerStream.getContentsAsString()
}
)

return new Promise((resolve, reject) => {
// we need to poll to see if the websocket finished writing to the stream
let timerId = setInterval(() => {
if (output) {
clearInterval(timerId)
timerId = -1 // reset timer
resolve(self.parseLsOutput(output))
}
}, 100)
}

// timout polling and throw error
setTimeout(() => {
if (timerId > 0) {
clearInterval(timerId)
reject(new FullstackTestingError(`timeout occurred while checking path: ${destPath}`))
}
}, timeout)
})
return items
} catch (e) {

throw new FullstackTestingError(`error occurred during listDir operation for path: ${destPath}: ${e.message}`, e)
}
}

Expand Down Expand Up @@ -430,6 +385,65 @@ export class Kubectl2 {
}
}

/**
* Invoke bash command within a container and return the console output as string
*
* @param podName pod name
* @param containerName container name
* @param command bash commands as an array to be run within the containerName (e.g 'ls -la /opt/hgcapp')
* @param timeoutMs timout in milliseconds
* @returns {Promise<string>} console output as string
*/
async getExecOutput (podName, containerName, command = [], timeoutMs = 5000) {
try {
if (!command) return ''

const execInstance = new k8s.Exec(this._kubeConfig)
const outStream = new sb.WritableStreamBuffer()
const errStream = new sb.WritableStreamBuffer()
let execStatus = 'Failure'

await execInstance.exec(
this.getCurrentNamespace(),
podName,
containerName,
command,
outStream,
errStream,
null,
false,
({ status }) => {
execStatus = status
if (status === 'Failure' || errStream.size()) {
throw new FullstackTestingError(`Error - details: \n ${errStream.getContentsAsString()}`)
}
}
)

// we need to poll to get the output contents
const pollingDelay = 100
return new Promise((resolve, reject) => {
let resolved = false
const timerId = setInterval(() => {
if (execStatus === 'Success') {
clearInterval(timerId)
resolved = true
resolve(outStream.getContentsAsString())
}
}, pollingDelay)

setTimeout(() => {
if (!resolved) {
clearInterval(timerId)
reject(new FullstackTestingError(`timeout occurred during exec in '${podName}:${containerName}': ${command.join[' ']}`))
}
}, timeoutMs)
})
} catch (e) {
throw new FullstackTestingError(`error occurred during exec in '${podName}:${containerName}': ${command.join[' ']}`)
}
}

/**
* Invoke `kubectl port-forward svc/<svc name>` command
* @param resource name of the service or podName. Must be of the format podName/<podName name> or svc/<service name>
Expand Down Expand Up @@ -496,14 +510,4 @@ export class Kubectl2 {
// clearTimeout(timerId)
// return true
// }

/**
* Invoke bash command within a containerName
* @param podName a kubernetes podName name
* @param containerName name of the containerName within the podName
* @param bashScript bash script to be run within the containerName (e.g 'ls -la /opt/hgcapp')
* @returns {Promise<Array>} console output as an array of strings
*/
async execContainer (podName, containerName, bashScript) {
}
}
4 changes: 2 additions & 2 deletions fullstack-network-manager/test/e2e/core/kubectl_e2e.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { describe, expect, it } from '@jest/globals'
import fs from 'fs'
import os from 'os'
import path from 'path'
import { v4 as uuidv4 } from 'uuid'
import { v4 as uuid4 } from 'uuid'
import { FullstackTestingError } from '../../../src/core/errors.mjs'
import { constants, Templates } from '../../../src/core/index.mjs'
import { Kubectl2 } from '../../../src/core/kubectl2.mjs'
Expand Down Expand Up @@ -31,7 +31,7 @@ describe('Kubectl', () => {
})

it('should be able to create and delete a namespaces', async () => {
const name = uuidv4()
const name = uuid4()
await expect(kubectl.createNamespace(name)).resolves.toBeTruthy()
await expect(kubectl.deleteNamespace(name)).resolves.toBeTruthy()
})
Expand Down

0 comments on commit fc26a01

Please sign in to comment.