-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for seeding volumes on kubernetes Co-authored-by: Michael Muesch <michael.muesch@architect.io> Co-authored-by: TJ Higgins <tj@architect.io>
- Loading branch information
1 parent
b548dec
commit 711abe7
Showing
11 changed files
with
782 additions
and
87 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import execa from 'execa'; | ||
import path from 'path'; | ||
import { ArchitectPlugin, PluginArchitecture, PluginBinary, PluginBundleType, PluginOptions, PluginPlatform } from './plugin-types'; | ||
|
||
export default class OrasPlugin implements ArchitectPlugin { | ||
private plugin_directory = ''; | ||
private binary?: PluginBinary; | ||
|
||
version = '0.15.0'; | ||
name: string = OrasPlugin.name; | ||
binaries: PluginBinary[] = [ | ||
{ | ||
platform: PluginPlatform.WINDOWS, | ||
architecture: PluginArchitecture.AMD64, | ||
bundle_type: PluginBundleType.ZIP, | ||
executable_path: 'oras.exe', | ||
url: 'https://github.com/oras-project/oras/releases/download/v0.15.0/oras_0.15.0_windows_amd64.zip', | ||
sha256: 'f8a43b8f3b1caf0a3c3a2204a7eab597d3a9241b1e0673c4d8a23ad439cd652a', | ||
}, | ||
{ | ||
platform: PluginPlatform.LINUX, | ||
architecture: PluginArchitecture.AMD64, | ||
bundle_type: PluginBundleType.TAR_GZ, | ||
executable_path: 'oras', | ||
url: 'https://github.com/oras-project/oras/releases/download/v0.15.0/oras_0.15.0_linux_amd64.tar.gz', | ||
sha256: '529c9d567f212093bc01c508b71b922fc6c6cbc74767d3b2eb7f9f79d534e718', | ||
}, | ||
{ | ||
platform: PluginPlatform.DARWIN, | ||
architecture: PluginArchitecture.AMD64, | ||
bundle_type: PluginBundleType.TAR_GZ, | ||
executable_path: 'oras', | ||
url: 'https://github.com/oras-project/oras/releases/download/v0.15.0/oras_0.15.0_darwin_amd64.tar.gz', | ||
sha256: '0724f64f38f9389497da71795751e5f1b48fd4fc43aa752241b020c0772d5cd8', | ||
}, | ||
{ | ||
platform: PluginPlatform.DARWIN, | ||
architecture: PluginArchitecture.ARM64, | ||
bundle_type: PluginBundleType.TAR_GZ, | ||
executable_path: 'oras', | ||
url: 'https://github.com/oras-project/oras/releases/download/v0.15.0/oras_0.15.0_darwin_arm64.tar.gz', | ||
sha256: '7889cee33ba2147678642cbd909be81ec9996f62c57c53b417f7c21c8d282334', | ||
}, | ||
]; | ||
|
||
async setup(pluginDirectory: string, binary: PluginBinary): Promise<void> { | ||
this.binary = binary; | ||
this.plugin_directory = pluginDirectory; | ||
} | ||
|
||
async exec(args: string[], opts: PluginOptions): Promise<execa.ExecaChildProcess<string> | undefined> { | ||
if (process.env.TEST === '1') { | ||
return undefined; | ||
} | ||
|
||
const cmd = execa(path.join(this.plugin_directory, `/${this.binary?.executable_path}`), args, opts.execa_options); | ||
if (opts.stdout) { | ||
cmd.stdout?.pipe(process.stdout); | ||
cmd.stderr?.pipe(process.stderr); | ||
} | ||
return cmd; | ||
} | ||
|
||
async push(url: string, tarFile: string, cwd: string): Promise<void> { | ||
await this.exec(['push', url, tarFile], { | ||
stdout: true, | ||
execa_options: { | ||
cwd: cwd, | ||
}, | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import * as fs from 'fs-extra'; | ||
import path from 'path'; | ||
import { Dictionary } from '../..'; | ||
import { ArchitectPlugin, PluginArchitecture, PluginBundleType, PluginPlatform } from './plugin-types'; | ||
import PluginUtils from './plugin-utils'; | ||
|
||
export default class PluginManager { | ||
private static readonly plugins: Dictionary<ArchitectPlugin> = {}; | ||
|
||
private static readonly ARCHITECTURE_MAP: Dictionary<PluginArchitecture> = { | ||
'x64': PluginArchitecture.AMD64, | ||
'arm64': PluginArchitecture.ARM64, | ||
}; | ||
|
||
private static readonly OPERATIN_SYSTEM_MAP: Dictionary<PluginPlatform> = { | ||
'win32': PluginPlatform.WINDOWS, | ||
'darwin': PluginPlatform.DARWIN, | ||
'linux': PluginPlatform.LINUX, | ||
}; | ||
|
||
private static getPlatform(): PluginPlatform { | ||
return this.OPERATIN_SYSTEM_MAP[process.platform]; | ||
} | ||
|
||
private static getArchitecture(): PluginArchitecture { | ||
return this.ARCHITECTURE_MAP[process.arch]; | ||
} | ||
|
||
private static async removeOldPluginVersions(pluginDirectory: string, version: string) { | ||
if (!(await fs.pathExists(pluginDirectory))) { | ||
return; | ||
} | ||
const downloaded_versions = await fs.readdir(pluginDirectory); | ||
for (const downloaded_version of downloaded_versions) { | ||
if (downloaded_version === version) { | ||
continue; | ||
} | ||
await fs.remove(path.join(pluginDirectory, downloaded_version)); | ||
} | ||
} | ||
|
||
static async getPlugin<T extends ArchitectPlugin>(pluginDirectory: string, ctor: { new(): T; }): Promise<T> { | ||
if (this.plugins[ctor.name]) { | ||
return this.plugins[ctor.name] as T; | ||
} | ||
const plugin = new ctor(); | ||
const current_plugin_directory = path.join(pluginDirectory, `/${plugin.name}`); | ||
const version_path = path.join(current_plugin_directory, `/${plugin.version}`); | ||
|
||
await this.removeOldPluginVersions(current_plugin_directory, plugin.version); | ||
await fs.mkdirp(version_path); | ||
|
||
const binary = PluginUtils.getBinary(plugin.binaries, this.getPlatform(), this.getArchitecture()); | ||
const downloaded_file_path = path.join(version_path, `/${plugin.name}.${binary.bundle_type === PluginBundleType.ZIP ? 'zip' : 'tar.gz'}`); | ||
|
||
if (!(await fs.pathExists(path.join(version_path, `/${binary.executable_path}`)))) { | ||
await PluginUtils.downloadFile(binary.url, downloaded_file_path, binary.sha256); | ||
await PluginUtils.extractFile(downloaded_file_path, version_path, binary.bundle_type); | ||
await fs.remove(downloaded_file_path); | ||
} | ||
|
||
await plugin.setup(version_path, PluginUtils.getBinary(plugin.binaries, this.getPlatform(), this.getArchitecture())); | ||
|
||
this.plugins[ctor.name] = plugin; | ||
return plugin as T; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import execa, { Options } from 'execa'; | ||
|
||
export enum PluginArchitecture { | ||
AMD64, ARM64 | ||
} | ||
|
||
export enum PluginPlatform { | ||
LINUX, DARWIN, WINDOWS | ||
} | ||
|
||
export enum PluginBundleType { | ||
ZIP, TAR_GZ | ||
} | ||
|
||
export interface PluginOptions { | ||
stdout: boolean; | ||
execa_options?: Options<string>; | ||
} | ||
|
||
export interface PluginBinary { | ||
url: string; | ||
architecture: PluginArchitecture; | ||
platform: PluginPlatform; | ||
sha256: string; | ||
bundle_type: PluginBundleType; | ||
executable_path: string; | ||
} | ||
|
||
export interface ArchitectPlugin { | ||
version: string; | ||
name: string; | ||
binaries: PluginBinary[]; | ||
setup(pluginDirectory: string, binary: PluginBinary): Promise<void>; | ||
exec(args: string[], opts: PluginOptions): Promise<execa.ExecaChildProcess<string> | undefined>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import AdmZip from 'adm-zip'; | ||
import axios from 'axios'; | ||
import * as crypto from 'crypto'; | ||
import * as fs from 'fs-extra'; | ||
import { createWriteStream } from 'fs-extra'; | ||
import { finished } from 'stream'; | ||
import * as tar from 'tar'; | ||
import { promisify } from 'util'; | ||
import { PluginArchitecture, PluginBinary, PluginBundleType, PluginPlatform } from './plugin-types'; | ||
|
||
export default class PluginUtils { | ||
static async downloadFile(url: string, location: string, sha256: string): Promise<void> { | ||
const writer = createWriteStream(location); | ||
return axios({ | ||
method: 'get', | ||
url: url, | ||
responseType: 'stream', | ||
}).then(async response => { | ||
response.data.pipe(writer); | ||
await promisify(finished)(writer); | ||
const fileBuffer = fs.readFileSync(location); | ||
const hashSum = crypto.createHash('sha256'); | ||
hashSum.update(fileBuffer); | ||
const hex = hashSum.digest('hex'); | ||
if (hex !== sha256) { | ||
throw new Error(`Unable to verify ${url}. Please contact Architect support for help.`); | ||
} | ||
}); | ||
} | ||
|
||
static async extractFile(file: string, location: string, bundleType: PluginBundleType): Promise<void> { | ||
if (bundleType === PluginBundleType.TAR_GZ) { | ||
await tar.extract({ file, C: location }); | ||
} else if (bundleType === PluginBundleType.ZIP) { | ||
const zip = new AdmZip(file); | ||
zip.extractAllTo(location); | ||
} | ||
} | ||
|
||
static getBinary(binaries: PluginBinary[], platform: PluginPlatform, architecture: PluginArchitecture): PluginBinary { | ||
for (const binary of binaries) { | ||
if (binary.platform === platform && binary.architecture === architecture) { | ||
return binary; | ||
} | ||
} | ||
throw new Error(`Unable to find proper binary for ${PluginPlatform[platform]}:${PluginArchitecture[architecture]}. Please contact Architect support for help.`); | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.