Init: Create & Init dayu Project...

Signed-off-by: MiaoWoo <admin@yumc.pw>
master
MiaoWoo 2019-07-03 15:50:59 +08:00
commit c47137ec4a
92 changed files with 2793 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
node_modules
dist
package-lock.json
yarn.lock

38
http/dayu.http Normal file
View File

@ -0,0 +1,38 @@
@url=https://faas.n.yumc.pw
### System
##### Info
GET {{url}}/info
##### Version
GET {{url}}/version
##### Events
GET {{url}}/events
### Swarm
@swarm={{url}}/swarm
##### Swarm Info
GET {{swarm}}/info
### Swarm Init
POST {{swarm}}/init
{}
### Stack
@stack={{url}}/stack
##### Stack List
GET {{stack}}/list
##### Stack Remove
POST {{stack}}/develop/remove
### Container
@container={{url}}/container
##### Container logs
@id=6365041d2e52c5896dd14a5450920e482dddc33e6addaa07fab413bcda78d723
GET {{container}}/{{id}}/logs

36
http/docker.http Normal file
View File

@ -0,0 +1,36 @@
@url=https://dcli.yumc.pw/v1.39
### Info
GET {{url}}/info
### Version
GET {{url}}/version
### Swarm
GET {{url}}/swarm
### Swarm Init
POST {{url}}/swarm/init
{}
### Node
GET {{url}}/nodes
### Container
@cid=87514be54f3b9a34ac8ea74097d2053d73c7c535f34d3446bcbe16d6f2ba0f0f
@container={{url}}/containers
##### List
GET {{container}}/json?filters={"label":{"com.docker.stack.namespace%3Dmonitor":false}}
##### In
GET {{container}}/{{cid}}/json
### Services
GET {{url}}/services?filters={"mode":["global"]}
### Create Services
POST {{url}}/services/create
{
}

27
lerna.json Normal file
View File

@ -0,0 +1,27 @@
{
"npmClient": "yarn",
"useWorkspaces": true,
"version": "0.3.3",
"changelog": {
"labels": {
"tag: new feature": ":rocket: New Feature",
"tag: breaking change": ":boom: Breaking Change",
"tag: bug fix": ":bug: Bug Fix",
"tag: enhancement": ":nail_care: Enhancement",
"tag: documentation": ":memo: Documentation",
"tag: internal": ":house: Internal"
},
"cacheDir": ".changelog"
},
"packages": [
"packages/*"
],
"command": {
"run": {
"stream": true
},
"publish": {
"registry": "https://repo.yumc.pw/repository/npm-hosted/"
}
}
}

20
package.json Normal file
View File

@ -0,0 +1,20 @@
{
"private": true,
"name": "dayu",
"version": "1.0.0",
"main": "index.js",
"author": "MiaoWoo <admin@yumc.pw>",
"license": "MIT",
"scripts": {
"clean": "npx lerna run clean",
"watch": "npx lerna run watch --concurrency 10",
"build": "npx lerna run build",
"lp": "npx lerna publish"
},
"workspaces": [
"packages/*"
],
"devDependencies": {
"lerna": "^3.14.1"
}
}

4
packages/common/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/node_modules
/dist
/package-lock.json
/yarn.lock

View File

@ -0,0 +1,22 @@
src
test
typings
bundled
build
coverage
docs
wiki
gulpfile.js
bower.json
karma.conf.js
tsconfig.json
typings.json
CONTRIBUTING.md
ISSUE_TEMPLATE.md
PULL_REQUEST_TEMPLATE.md
tslint.json
wallaby.js
.travis.yml
.gitignore
.vscode
type_definitions

11
packages/common/README.md Normal file
View File

@ -0,0 +1,11 @@
# `@dayu/common`
> TODO: description
## Usage
```
const core = require('@dayu/common');
// TODO: DEMONSTRATE API
```

View File

@ -0,0 +1,27 @@
{
"name": "@dayu/common",
"version": "0.0.1",
"description": "> TODO: description",
"author": "MiaoWoo <admin@yumc.pw>",
"homepage": "https://github.com/circlecloud/dayu",
"license": "ISC",
"main": "dist/index.js",
"publishConfig": {
"registry": "https://repo.yumc.pw/repository/npm-hosted/"
},
"scripts": {
"dev": "npx ts-node-dev src/index.ts",
"clean": "rimraf dist",
"watch": "npx tsc --watch",
"build": "yarn clean && npx tsc",
"test": "echo \"Error: run tests from root\" && exit 1"
},
"dependencies": {
"axios": "^0.19.0"
},
"devDependencies": {
"rimraf": "^2.6.3",
"ts-node-dev": "^1.0.0-pre.40",
"typescript": "^3.5.2"
}
}

View File

@ -0,0 +1,28 @@
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/socket.io-client@2.2.0/dist/socket.io.js"> </script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@3.12.2/dist/xterm.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@3.12.2/dist/addons/fullscreen/fullscreen.css">
<script src="https://cdn.jsdelivr.net/npm/xterm@3.12.2/dist/xterm.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xterm@3.12.2/dist/addons/fit/fit.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xterm@3.12.2/dist/addons/attach/attach.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xterm@3.12.2/dist/addons/fullscreen/fullscreen.js"></script>
<style>
#terminal-container .terminal.xterm {
height: 100%;
}
#terminal-container .xterm-viewport {
height: 100% !important;
}
</style>
</head>
<body>
<div id="terminal" style="height: 100%;"></div>
<script type="text/javascript" src="js/index.js"></script>
</body>
</html>

View File

@ -0,0 +1,68 @@
let command = '';
Terminal.applyAddon(fit);
Terminal.applyAddon(attach);
Terminal.applyAddon(fullscreen);
var term = new Terminal({
experimentalCharAtlas: 'dynamic',
cursorBlink: false,
});
term.open(document.getElementById('terminal'));
term.toggleFullScreen();
term.fit();
window.onresize = function() {
term.fit();
}
let query = {}
location.search.substring(1).split("&").forEach(q => {
let qy = q.split("=", 2);
query[qy[0]] = qy[1]
})
console.log(query);
var socket = io('/container', {
path: '/ws',
transports: ['websocket']
});
socket.on('connect', () => {
term.writeln('connect')
if (query.action) {
term.writeln(`Recover Action: ${query.action} Data: ${query.data}`)
switch (query.action) {
case "container":
socket.emit('logs', {
id: query.data,
since: Date.now() / 1000 - 60 * 15,
until: Date.now() / 1000,
stderr: false,
tail: "all"
})
break;
default:
}
}
});
term.on('data', async data => {
if (data == '\t') {
return;
}
term.write(data);
if (data == '\r') {
term.write('\n');
socket.emit('logs', {
id: command
})
command = '';
} else {
command += data;
}
});
socket.on('message', data => {
term.write(data.toString() + '\r\n');
});
socket.on('disconnect', () => {
term.reset();
term.writeln('disconnect');
});

View File

@ -0,0 +1,68 @@
import * as http from 'http'
import axios, { AxiosResponse, AxiosRequestConfig, Method, AxiosInstance } from 'axios'
class HttpClient {
private api: AxiosInstance;
constructor() {
const instanceConfig: AxiosRequestConfig = {
headers: {
'Content-Type': 'application/json'
},
timeout: 5000
}
if (process.env.DOCKER_HOST.startsWith("/")) {
instanceConfig.socketPath = process.env.DOCKER_HOST
} else {
instanceConfig.baseURL = process.env.DOCKER_HOST
}
this.api = axios.create(instanceConfig)
}
async get<T = any>(path: string, data?: object): Promise<T> {
return await this.handle<T>("GET", path, { params: data });
}
async post<T = any>(path: string, data?: object): Promise<T> {
return await this.handle<T>("POST", path, { data });
}
async stream<T = http.ServerResponse>(path: string, data?: object): Promise<T> {
return await this.handle<T>("GET", path, { params: data, responseType: "stream" });
}
async handle<T>(method: Method, path: string, reqConfig?: AxiosRequestConfig): Promise<T> {
let config: AxiosRequestConfig = {
method,
url: path,
};
let startTime = Date.now();
Object.assign(config, reqConfig)
let response: AxiosResponse;
try {
response = await this.api.request(config);
return response.data as T
} catch (ex) {
if (!ex.response) { throw ex; }
response = ex.response;
if (this.isStream(response)) {
let stream = response.data;
response.data = await new Promise<T>((resolve, reject) => {
let cache = '';
stream.on('data', (chunk: ArrayBuffer) => { cache += chunk.toString() })
stream.on('end', () => { resolve(JSON.parse(cache) as T); })
})
}
throw new Error(JSON.stringify(response.data));
} finally {
if (response) {
console.log(`============== API Invoke ==============
REQUEST METHOD : ${method}
REQUEST PATH : ${axios.getUri(config)}
REQUEST PARAMS : ${JSON.stringify(config.params || {})}
REQUEST BODY : ${JSON.stringify(config.data || {})}
RESPONSE BODY : ${this.isStream(response) ? '<Stream>' : JSON.stringify(response.data)}
HANDLE TIME : ${Date.now() - startTime}ms
========================================`);
}
}
}
isStream(response: AxiosResponse) {
return toString.call(response.data.pipe) === "[object Function]";
}
}

View File

@ -0,0 +1 @@
export * from './api'

View File

@ -0,0 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": "src",
"outDir": "dist"
}
}

4
packages/core/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/node_modules
/dist
/package-lock.json
/yarn.lock

22
packages/core/.npmignore Normal file
View File

@ -0,0 +1,22 @@
src
test
typings
bundled
build
coverage
docs
wiki
gulpfile.js
bower.json
karma.conf.js
tsconfig.json
typings.json
CONTRIBUTING.md
ISSUE_TEMPLATE.md
PULL_REQUEST_TEMPLATE.md
tslint.json
wallaby.js
.travis.yml
.gitignore
.vscode
type_definitions

11
packages/core/README.md Normal file
View File

@ -0,0 +1,11 @@
# `@dayu/core`
> TODO: description
## Usage
```
const core = require('@dayu/core');
// TODO: DEMONSTRATE API
```

View File

@ -0,0 +1,33 @@
{
"name": "@dayu/core",
"version": "0.0.1",
"description": "> TODO: description",
"author": "MiaoWoo <admin@yumc.pw>",
"homepage": "https://github.com/circlecloud/dayu",
"license": "ISC",
"main": "dist/index.js",
"publishConfig": {
"registry": "https://repo.yumc.pw/repository/npm-hosted/"
},
"scripts": {
"dev": "npx ts-node-dev --respawn --prefer-ts --debounce=1500 --ignore-watch=[] --project tsconfig.json",
"debug": "npx nodemon -V --watch ../../node_modules --delay 1500ms dist/index.js",
"clean": "rimraf dist",
"watch": "npx tsc --watch",
"build": "yarn clean && npx tsc",
"test": "echo \"Error: run tests from root\" && exit 1"
},
"dependencies": {
"@cc-server/core": "^0.6.1",
"@cc-server/ws": "^0.6.1",
"@dayu/docker-api": "^0.0.1",
"axios": "^0.19.0"
},
"devDependencies": {
"@types/express": "^4.17.0",
"@types/socket.io": "^2.1.2",
"rimraf": "^2.6.3",
"ts-node-dev": "^1.0.0-pre.40",
"typescript": "^3.5.2"
}
}

View File

@ -0,0 +1,28 @@
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/socket.io-client@2.2.0/dist/socket.io.js"> </script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@3.12.2/dist/xterm.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@3.12.2/dist/addons/fullscreen/fullscreen.css">
<script src="https://cdn.jsdelivr.net/npm/xterm@3.12.2/dist/xterm.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xterm@3.12.2/dist/addons/fit/fit.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xterm@3.12.2/dist/addons/attach/attach.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xterm@3.12.2/dist/addons/fullscreen/fullscreen.js"></script>
<style>
#terminal-container .terminal.xterm {
height: 100%;
}
#terminal-container .xterm-viewport {
height: 100% !important;
}
</style>
</head>
<body>
<div id="terminal" style="height: 100%;"></div>
<script type="text/javascript" src="js/index.js"></script>
</body>
</html>

View File

@ -0,0 +1,68 @@
let command = '';
Terminal.applyAddon(fit);
Terminal.applyAddon(attach);
Terminal.applyAddon(fullscreen);
var term = new Terminal({
experimentalCharAtlas: 'dynamic',
cursorBlink: false,
});
term.open(document.getElementById('terminal'));
term.toggleFullScreen();
term.fit();
window.onresize = function() {
term.fit();
}
let query = {}
location.search.substring(1).split("&").forEach(q => {
let qy = q.split("=", 2);
query[qy[0]] = qy[1]
})
console.log(query);
var socket = io('/container', {
path: '/ws',
transports: ['websocket']
});
socket.on('connect', () => {
term.writeln('connect')
if (query.action) {
term.writeln(`Recover Action: ${query.action} Data: ${query.data}`)
switch (query.action) {
case "container":
socket.emit('logs', {
id: query.data,
since: Date.now() / 1000 - 60 * 15,
until: Date.now() / 1000,
stderr: false,
tail: "all"
})
break;
default:
}
}
});
term.on('data', async data => {
if (data == '\t') {
return;
}
term.write(data);
if (data == '\r') {
term.write('\n');
socket.emit('logs', {
id: command
})
command = '';
} else {
command += data;
}
});
socket.on('message', data => {
term.write(data.toString() + '\r\n');
});
socket.on('disconnect', () => {
term.reset();
term.writeln('disconnect');
});

View File

@ -0,0 +1,36 @@
import * as docker from '@dayu/docker-api'
import { io, interfaces, namespace, listener, Message } from '@cc-server/ws'
import { controller, httpGet, requestParam } from '@cc-server/binding'
@controller('/container')
class ContainerController {
@httpGet('/list')
public async list() {
return await docker.container.list({
filters: JSON.stringify({
})
});
}
@httpGet('/:id')
public async info(@requestParam('id') id: string) {
return await docker.container;
}
}
@namespace("/container")
class ContainerNamespace extends interfaces.Namespace {
@listener()
async logs(socket: io.Socket, data: any) {
try {
let stream = await docker.container.logs(data.id, data);
this.defer(socket, () => stream.connection.destroy());
stream.on('data', (chunk: ArrayBuffer) => {
let log = Buffer.from(chunk.slice(8, chunk.byteLength - 1)).toString();
socket.send(log);
})
} catch (ex) {
return new Message(ex.message);
}
}
}

View File

@ -0,0 +1,10 @@
import { controller, httpGet, httpPost } from 'inversify-express-utils';
import * as docker from '@dayu/docker-api'
@controller('/node')
class NodeController {
@httpGet('/list')
public async list() {
return await docker.node.list();
}
}

View File

@ -0,0 +1,41 @@
import { controller, httpGet, httpPost, requestParam } from 'inversify-express-utils';
import * as docker from '@dayu/docker-api'
const STACK_LABEL = 'com.docker.stack.namespace';
@controller('/stack')
class StackController {
@httpGet('/list')
public async list() {
let stacks: { [key: string]: string[] } = {};
let services = await docker.service.list();
for (const service of services) {
let stackName = service.Spec.Labels[STACK_LABEL]
if (stackName) {
let stack = stacks[stackName] || [];
stack.push(service.Spec.Name);
stacks[stackName] = stack;
}
}
return stacks;
}
@httpGet('/:stack')
public async details(@requestParam('stack') stack: string) {
let filter: any = {}
filter[`${STACK_LABEL}=${stack}`] = true
let filterOpt = {
filters: JSON.stringify({
"label": filter
})
}
let services = await docker.service.list(filterOpt)
let networks = await docker.network.list(filterOpt)
let containers = await docker.container.list(filterOpt);
return {
services: services.map(service => service.Spec.Name),
networks: networks.map(network => network.Name),
containers: containers.map(container => container.Names[0].substring(1))
}
}
}

View File

@ -0,0 +1,24 @@
import { controller, httpGet, httpPost } from 'inversify-express-utils';
import * as docker from '@dayu/docker-api'
@controller('/swarm')
class SwarmController {
@httpGet('/info')
public async version() {
return await docker.swarm.inspect();
}
@httpPost('/init')
public async info() {
let info = await docker.swarm.init({
ListenAddr: "0.0.0.0:2377",
AdvertiseAddr: "192.168.0.3:2377",
// DefaultAddrPool: [
// "10.10.0.0/8",
// "20.20.0.0/8"
// ],
// ForceNewCluster: false,
// SubnetSize: 24
})
return info;
}
}

View File

@ -0,0 +1,22 @@
import { controller, httpGet, httpPost } from 'inversify-express-utils';
import * as docker from '@dayu/docker-api'
@controller('')
class SystemController {
@httpGet('/version')
public async version() {
return await docker.system.version()
}
@httpGet('/info')
public async info() {
let info = await docker.system.info()
return info;
}
@httpGet('/events')
public async event() {
await docker.system.events((event) => {
if (!event) { return }
console.log(event)
})
}
}

View File

@ -0,0 +1,21 @@
import { CcServerBoot } from '@cc-server/core'
import * as fs from 'fs'
import * as path from 'path'
//process.env.DOCKER_HOST = 'https://ndcli.yumc.pw'
process.env.DOCKER_HOST = '/var/run/docker.sock'
let server = new CcServerBoot();
let modulesDir = path.join(__dirname, 'controller')
let list = fs.readdirSync(modulesDir);
for (let file of list) {
let moduleDir = path.join(modulesDir, file)
let stat = fs.statSync(moduleDir);
if (stat.isFile() && file.endsWith('.js')) {
require(moduleDir);
}
}
server.static().build().start();

View File

@ -0,0 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": "src",
"outDir": "dist"
}
}

4
packages/docker-api/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/node_modules
/dist
/package-lock.json
/yarn.lock

View File

@ -0,0 +1,22 @@
src
test
typings
bundled
build
coverage
docs
wiki
gulpfile.js
bower.json
karma.conf.js
tsconfig.json
typings.json
CONTRIBUTING.md
ISSUE_TEMPLATE.md
PULL_REQUEST_TEMPLATE.md
tslint.json
wallaby.js
.travis.yml
.gitignore
.vscode
type_definitions

View File

@ -0,0 +1,11 @@
# `@dayu/core`
> TODO: description
## Usage
```
const core = require('@dayu/core');
// TODO: DEMONSTRATE API
```

View File

@ -0,0 +1,29 @@
{
"name": "@dayu/docker-api",
"version": "0.0.1",
"description": "> TODO: description",
"author": "MiaoWoo <admin@yumc.pw>",
"homepage": "https://github.com/circlecloud/dayu",
"license": "ISC",
"main": "dist/index.js",
"publishConfig": {
"registry": "https://repo.yumc.pw/repository/npm-hosted/"
},
"scripts": {
"dev": "npx ts-node-dev src/index.ts",
"clean": "rimraf dist",
"watch": "npx tsc --watch",
"build": "yarn clean && npx tsc",
"test": "echo \"Error: run tests from root\" && exit 1"
},
"dependencies": {
"@cc-server/core": "^0.3.3",
"axios": "^0.19.0"
},
"devDependencies": {
"@types/node": "^12.0.10",
"ts-node-dev": "^1.0.0-pre.40",
"typescript": "^3.5.2",
"rimraf": "^2.6.3"
}
}

View File

@ -0,0 +1,11 @@
export interface ObjectMap {
[key: string]: {};
}
export interface StringMap {
[key: string]: string;
}
export type PortSet = ObjectMap
export type Options = StringMap
export type Config = StringMap
export type Labels = StringMap
export type Ports = StringMap | ObjectMap

View File

@ -0,0 +1,10 @@
export declare namespace query {
export interface FilterOpt {
filters?: string;
}
export interface LabelOpt {
[key: string]: {
[key: string]: boolean
}
}
}

View File

@ -0,0 +1,18 @@
import * as common from './common'
export declare namespace container {
export interface ListOpts extends common.query.FilterOpt {
all?: boolean;
limit?: number;
size?: boolean;
}
export interface LogsOpts {
follow?: boolean;
stdout?: boolean;
stderr?: boolean;
since?: number;
until?: number;
timestamps?: boolean;
tail?: number | "all";
}
}

View File

@ -0,0 +1,5 @@
export * from './swarm'
export * from './common'
export * from './network'
export * from './service'
export * from './container'

View File

@ -0,0 +1,6 @@
import * as common from './common'
export declare namespace network {
export interface ListOpts extends common.query.FilterOpt {
}
}

View File

@ -0,0 +1,6 @@
import * as common from './common'
export declare namespace service {
export interface ListOpts extends common.query.FilterOpt {
}
}

View File

@ -0,0 +1,59 @@
import { Labels } from '../common'
export declare namespace swarm {
type NodeAvailability = string;
export interface InitOpts {
ListenAddr?: string;
AdvertiseAddr?: string;
DefaultAddrPool?: string[];
DataPathAddr?: string;
DataPathPort?: number;
SubnetSize?: number;
ForceNewCluster?: boolean;
Availability?: NodeAvailability;
Spec?: Spec;
}
export interface Spec {
Name?: string;
Labels?: Labels;
Orchestration?: Orchestration;
Raft?: Raft;
Dispatcher?: Dispatcher;
CAConfig?: CAConfig;
TaskDefaults?: TaskDefaults;
EncryptionConfig?: EncryptionConfig;
}
export interface Version {
Index: number;
}
export interface Orchestration {
TaskHistoryRetentionLimit?: number;
}
export interface Raft {
SnapshotInterval?: number;
KeepOldSnapshots?: number;
LogEntriesForSlowFollowers?: number;
ElectionTick?: number;
HeartbeatTick?: number;
}
export interface Dispatcher {
HeartbeatPeriod?: number;
}
export interface CAConfig {
NodeCertExpiry?: number;
}
export interface TaskDefaults {
}
export interface EncryptionConfig {
AutoLockManagers?: boolean;
}
}

View File

@ -0,0 +1,300 @@
import { Labels, Config as CommonConfig, Ports, Options, StringMap, ObjectMap } from '../common'
export declare namespace container {
export interface ContainerState {
Status: string;
Running: boolean;
Paused: boolean;
Restarting: boolean;
OOMKilled: boolean;
Dead: boolean;
Pid: number;
ExitCode: number;
Error: string;
StartedAt: string;
FinishedAt: Date;
}
export interface LogConfig {
Type: string;
Config: CommonConfig;
}
export interface PortBindings {
}
export interface RestartPolicy {
Name: string;
MaximumRetryCount: number;
}
// WeightDevice is a structure that holds device:weight pair
export interface WeightDevice {
Path: string;
Weight: number;
}
// ThrottleDevice is a structure that holds device:rate_per_second pair
export interface ThrottleDevice {
Path: string;
Rate: number;
}
// DeviceMapping represents the device mapping between the host and the container.
export interface DeviceMapping {
PathOnHost: string;
PathInContainer: string;
CgroupPermissions: string;
}
// DeviceRequest represents a request for devices from a device driver.
// Used by GPU device drivers.
export interface DeviceRequest {
Driver: string // Name of device driver
Count: number // Number of devices to request (-1 = All)
DeviceIDs: string[] // List of device IDs as recognizable by the device driver
Capabilities: string[][] // An OR list of AND lists of device capabilities (e.g. "gpu")
Options: StringMap // Options to pass onto the device driver
}
export interface Resources {
CpuShares?: number;
Memory?: number;
NanoCpus?: number;
CgroupParent?: string;
BlkioWeight?: number;
BlkioWeightDevice?: WeightDevice[];
BlkioDeviceReadBps?: ThrottleDevice[];
BlkioDeviceWriteBps?: ThrottleDevice[];
BlkioDeviceReadIOps?: ThrottleDevice[];
BlkioDeviceWriteIOps?: ThrottleDevice[];
CpuPeriod?: number;
CpuQuota?: number;
CpuRealtimePeriod?: number;
CpuRealtimeRuntime?: number;
CpusetCpus?: string;
CpusetMems?: string;
Devices?: DeviceMapping[];
DeviceCgroupRules?: string[];
DeviceRequests: DeviceRequest[];
DiskQuota?: number;
KernelMemory?: number;
MemoryReservation?: number;
MemorySwap?: number;
MemorySwappiness?: any;
OomKillDisable?: boolean;
PidsLimit?: number;
Ulimits?: any;
CpuCount?: number;
CpuPercent?: number;
IOMaximumIOps?: number;
IOMaximumBandwidth?: number;
}
export interface HostConfig extends Resources {
Binds?: any;
ContainerIDFile: string;
LogConfig: LogConfig;
NetworkMode: string;
PortBindings: PortBindings;
RestartPolicy: RestartPolicy;
AutoRemove: boolean;
VolumeDriver: string;
VolumesFrom?: any;
CapAdd?: any;
CapDrop?: any;
Dns?: any;
DnsOptions?: any;
DnsSearch?: any;
ExtraHosts?: any;
GroupAdd?: any;
IpcMode: string;
Cgroup: string;
Links?: any;
OomScoreAdj: number;
PidMode: string;
Privileged: boolean;
PublishAllPorts: boolean;
ReadonlyRootfs: boolean;
SecurityOpt?: any;
UTSMode: string;
UsernsMode: string;
ShmSize: number;
Runtime: string;
ConsoleSize: number[];
Isolation: string;
Mounts: Mount[];
MaskedPaths: string[];
ReadonlyPaths: string[];
}
export interface Data {
LowerDir: string;
MergedDir: string;
UpperDir: string;
WorkDir: string;
}
export interface GraphDriver {
Data: Data;
Name: string;
}
export type ExposedPorts = Ports
// HealthConfig holds configuration settings for the HEALTHCHECK feature.
export interface HealthConfig {
// Test is the test to perform to check that the container is healthy.
// An empty slice means to inherit the default.
// The options are:
// {} : inherit healthcheck
// {"NONE"} : disable healthcheck
// {"CMD", args...} : exec arguments directly
// {"CMD-SHELL", command} : run command with system's default shell
Test: string[];
// Zero means to inherit. Durations are expressed as integer nanoseconds.
Interval: number; // Interval is the time to wait between checks.
Timeout: number; // Timeout is the time to wait before considering the check to have hung.
StartPeriod: number; // The start period for the container to initialize before the retries starts to count down.
// Retries is the number of consecutive failures needed to consider a container as unhealthy.
// Zero means inherit.
Retries: number;
}
export interface Config {
Hostname: string;
Domainname: string;
User: string;
AttachStdin: boolean;
AttachStdout: boolean;
AttachStderr: boolean;
ExposedPorts: ExposedPorts;
Tty: boolean;
OpenStdin: boolean;
StdinOnce: boolean;
Env: string[];
Cmd?: any;
Healthcheck?: HealthConfig;
ArgsEscaped: boolean;
Image: string;
Volumes?: ObjectMap;
WorkingDir: string;
Entrypoint: string[];
NetworkDisabled: boolean;
MacAddress: string;
OnBuild?: any;
Labels: Labels;
StopSignal: string;
StopTimeout: number;
Shell: string[];
}
export interface IPAMConfig {
IPv4Address: string;
}
export interface Networks {
[key: string]: Network
}
export interface NetworkSettings {
Bridge: string;
SandboxID: string;
HairpinMode: boolean;
LinkLocalIPv6Address: string;
LinkLocalIPv6PrefixLen: number;
Ports: Ports;
SandboxKey: string;
SecondaryIPAddresses?: any;
SecondaryIPv6Addresses?: any;
EndpointID: string;
Gateway: string;
GlobalIPv6Address: string;
GlobalIPv6PrefixLen: number;
IPAddress: string;
IPPrefixLen: number;
IPv6Gateway: string;
MacAddress: string;
Networks: Networks;
}
export interface ContainerJSON {
Id: string;
Created: string;
Path: string;
Args: string[];
State: ContainerState;
Image: string;
ResolvConfPath: string;
HostnamePath: string;
HostsPath: string;
LogPath: string;
Name: string;
RestartCount: number;
Driver: string;
Platform: string;
MountLabel: string;
ProcessLabel: string;
AppArmorProfile: string;
ExecIDs?: any;
HostConfig: HostConfig;
GraphDriver: GraphDriver;
Mounts: Mount[];
Config: Config;
NetworkSettings: NetworkSettings;
}
export interface Port {
IP: string;
PrivatePort: number;
PublicPort: number;
Type: string;
}
export interface Network {
IPAMConfig?: IPAMConfig;
Links?: any;
Aliases?: any;
NetworkID: string;
EndpointID: string;
Gateway: string;
IPAddress: string;
IPPrefixLen: number;
IPv6Gateway: string;
GlobalIPv6Address: string;
GlobalIPv6PrefixLen: number;
MacAddress: string;
DriverOpts?: any;
}
export interface SummaryNetworkSettings {
Networks: Networks;
}
export interface Mount {
Type: string;
Name: string;
Source: string;
Destination: string;
Driver: string;
Mode: string;
RW: boolean;
Propagation: string;
}
export interface Container {
Id: string;
Names: string[];
Image: string;
ImageID: string;
Command: string;
Created: number;
Ports: Port[];
Labels: Labels;
State: string;
Status: string;
HostConfig: {
NetworkMode: string;
};
NetworkSettings: SummaryNetworkSettings;
Mounts: Mount[];
}
}

View File

@ -0,0 +1,6 @@
export * from './node'
export * from './swarm'
export * from './system'
export * from './network'
export * from './service'
export * from './container'

View File

@ -0,0 +1,70 @@
import { Labels, Options, StringMap } from '../common'
export declare namespace network {
export interface Config {
Subnet: string;
Gateway: string;
}
export interface IPAM {
Driver: string;
Options?: any;
Config: Config[];
}
export interface ConfigFrom {
Network: string;
}
export interface EndpointResource {
Name: string;
EndpointID: string;
MacAddress: string;
IPv4Address: string;
IPv6Address: string;
}
export interface Containers {
[key: string]: EndpointResource;
}
export interface PeerInfo {
Name: string;
IP: string;
}
// Task carries the information about one backend task
export interface Task {
Name: string;
EndpointID: string;
EndpointIP: string;
Info: StringMap;
}
export interface ServiceInfo {
VIP: string;
Ports: string;
LocalLBIndex: number;
Tasks: Task;
}
export interface NetworkResource {
Name: string;
Id: string;
Created: string;
Scope: string;
Driver: string;
EnableIPv6: boolean;
IPAM: IPAM;
Internal: boolean;
Attachable: boolean;
Ingress: boolean;
ConfigFrom: ConfigFrom;
ConfigOnly: boolean;
Containers?: Containers;
Options: Options;
Labels: Labels;
Peers: network.PeerInfo[];
Services: network.ServiceInfo[];
}
}

View File

@ -0,0 +1,71 @@
import { Labels } from '../common'
export declare namespace node {
export interface Version {
Index: number;
}
export interface Spec {
Labels: Labels;
Role: string;
Availability: string;
}
export interface Platform {
Architecture: string;
OS: string;
}
export interface Resources {
NanoCPUs: number;
MemoryBytes: number;
}
export interface Plugin {
Type: string;
Name: string;
}
export interface Engine {
EngineVersion: string;
Plugins: Plugin[];
}
export interface TLSInfo {
TrustRoot: string;
CertIssuerSubject: string;
CertIssuerPublicKey: string;
}
export interface Description {
Hostname: string;
Platform: Platform;
Resources: Resources;
Engine: Engine;
TLSInfo: TLSInfo;
}
export interface Status {
State: string;
Addr: string;
}
export interface ManagerStatus {
Leader: boolean;
Reachability: string;
Addr: string;
}
export interface Node {
ID: string;
Version: Version;
CreatedAt: string;
UpdatedAt: string;
Spec: Spec;
Description: Description;
Status: Status;
ManagerStatus: ManagerStatus;
}
}

View File

@ -0,0 +1,195 @@
import { Labels, Options } from '../common'
export declare namespace service {
export interface Version {
Index: number;
}
export interface Privileges {
CredentialSpec?: any;
SELinuxContext?: any;
}
export interface DriverConfig {
Options: Options;
}
export interface VolumeOptions {
Labels: Labels;
DriverConfig: DriverConfig;
}
export interface Mount {
Type: string;
Source: string;
Target: string;
VolumeOptions: VolumeOptions;
ReadOnly?: boolean;
}
export interface File {
Name: string;
UID: string;
GID: string;
Mode: number;
}
export interface Secret {
File: File;
SecretID: string;
SecretName: string;
}
export interface DNSConfig {
}
export interface ContainerSpec {
Image: string;
Labels: Labels;
Privileges: Privileges;
Mounts: Mount[];
Isolation: string;
Env: string[];
Secrets: Secret[];
Args: string[];
StopGracePeriod?: number;
DNSConfig: DNSConfig;
User: string;
}
export interface Limits {
MemoryBytes: any;
NanoCPUs?: number;
}
export interface Reservations {
MemoryBytes: any;
NanoCPUs?: number;
}
export interface Resources {
Limits: Limits;
Reservations: Reservations;
}
export interface Platform {
Architecture: string;
OS: string;
}
export interface Placement {
Constraints: string[];
Platforms: Platform[];
}
export interface Network {
Target: string;
Aliases: string[];
}
export interface RestartPolicy {
Condition: string;
Delay: any;
MaxAttempts: number;
Window: any;
}
export interface LogDriver {
Name: string;
Options: Options;
}
export interface TaskTemplate {
ContainerSpec: ContainerSpec;
Resources: Resources;
Placement: Placement;
Networks: Network[];
ForceUpdate: number;
Runtime: string;
RestartPolicy: RestartPolicy;
LogDriver: LogDriver;
}
export interface Replicated {
Replicas: number;
}
export interface Global {
}
export interface Mode {
Replicated: Replicated;
Global: Global;
}
export interface Port {
Protocol: string;
TargetPort: number;
PublishedPort: number;
PublishMode: string;
}
export interface EndpointSpec {
Mode: string;
Ports: Port[];
}
export interface UpdateConfig {
Parallelism: number;
FailureAction: string;
Monitor: number;
MaxFailureRatio: number;
Order: string;
}
export interface RollbackConfig {
Parallelism: number;
FailureAction: string;
Monitor: number;
MaxFailureRatio: number;
Order: string;
}
export interface Spec {
Name: string;
Labels: Labels;
TaskTemplate: TaskTemplate;
Mode: Mode;
EndpointSpec: EndpointSpec;
UpdateConfig: UpdateConfig;
RollbackConfig: RollbackConfig;
}
export interface VirtualIP {
NetworkID: string;
Addr: string;
}
export interface Endpoint {
Spec: Spec;
Ports: Port[];
VirtualIPs: VirtualIP[];
}
export interface PreviousSpec {
Name: string;
Labels: Labels;
TaskTemplate: TaskTemplate;
Mode: Mode;
EndpointSpec: EndpointSpec;
UpdateConfig: UpdateConfig;
RollbackConfig: RollbackConfig;
}
export interface Service {
ID: string;
Version: Version;
CreatedAt: string;
UpdatedAt: any;
Spec: Spec;
Endpoint: Endpoint;
PreviousSpec: PreviousSpec;
}
}

View File

@ -0,0 +1,70 @@
export declare namespace swarm {
export interface Version {
Index: number;
}
export interface Labels {
}
export interface Orchestration {
TaskHistoryRetentionLimit?: number;
}
export interface Raft {
SnapshotInterval?: number;
KeepOldSnapshots?: number;
LogEntriesForSlowFollowers?: number;
ElectionTick?: number;
HeartbeatTick?: number;
}
export interface Dispatcher {
HeartbeatPeriod?: number;
}
export interface CAConfig {
NodeCertExpiry?: number;
}
export interface TaskDefaults {
}
export interface EncryptionConfig {
AutoLockManagers?: boolean;
}
export interface Spec {
Name?: string;
Labels?: Labels;
Orchestration?: Orchestration;
Raft?: Raft;
Dispatcher?: Dispatcher;
CAConfig?: CAConfig;
TaskDefaults?: TaskDefaults;
EncryptionConfig?: EncryptionConfig;
}
export interface TLSInfo {
TrustRoot: string;
CertIssuerSubject: string;
CertIssuerPublicKey: string;
}
export interface JoinTokens {
Worker: string;
Manager: string;
}
export interface Info {
ID: string;
Version: Version;
CreatedAt: string;
UpdatedAt: string;
Spec: Spec;
TLSInfo: TLSInfo;
RootRotationInProgress: boolean;
DefaultAddrPool: string[];
SubnetSize: number;
JoinTokens: JoinTokens;
}
}

View File

@ -0,0 +1,224 @@
import { Labels, Options } from '../common'
export declare namespace system {
export class Plugins {
Volume: string[];
Network: string[];
Authorization?: any;
Log: string[];
}
export class DockerIo {
Name: string;
Mirrors: string[];
Secure: boolean;
Official: boolean;
}
export class IndexConfigs {
[key: string]: DockerIo;
}
export class RegistryConfig {
AllowNondistributableArtifactsCIDRs: any[];
AllowNondistributableArtifactsHostnames: any[];
InsecureRegistryCIDRs: string[];
IndexConfigs: IndexConfigs;
Mirrors: string[];
}
export class Runc {
path: string;
}
export class Runtimes {
runc: Runc;
}
export class RemoteManager {
NodeID: string;
Addr: string;
}
export class ClusterVersion {
Index: number;
}
export class Orchestration {
TaskHistoryRetentionLimit: number;
}
export class Raft {
SnapshotInterval: number;
KeepOldSnapshots: number;
LogEntriesForSlowFollowers: number;
ElectionTick: number;
HeartbeatTick: number;
}
export class Dispatcher {
HeartbeatPeriod: number;
}
export class CAConfig {
NodeCertExpiry: number;
}
export class TaskDefaults {
}
export class EncryptionConfig {
AutoLockManagers: boolean;
}
export class Spec {
Name: string;
Labels: Labels;
Orchestration: Orchestration;
Raft: Raft;
Dispatcher: Dispatcher;
CAConfig: CAConfig;
TaskDefaults: TaskDefaults;
EncryptionConfig: EncryptionConfig;
}
export class TLSInfo {
TrustRoot: string;
CertIssuerSubject: string;
CertIssuerPublicKey: string;
}
export class Cluster {
ID: string;
Version: ClusterVersion;
CreatedAt: string;
UpdatedAt: string;
Spec: Spec;
TLSInfo: TLSInfo;
RootRotationInProgress: boolean;
DefaultAddrPool: string[];
SubnetSize: number;
}
export class Swarm {
NodeID: string;
NodeAddr: string;
LocalNodeState: string;
ControlAvailable: boolean;
Error: string;
RemoteManagers: RemoteManager[];
Nodes: number;
Managers: number;
Cluster: Cluster;
}
export class ContainerdCommit {
ID: string;
Expected: string;
}
export class RuncCommit {
ID: string;
Expected: string;
}
export class InitCommit {
ID: string;
Expected: string;
}
export class Info {
ID: string;
Containers: number;
ContainersRunning: number;
ContainersPaused: number;
ContainersStopped: number;
Images: number;
Driver: string;
DriverStatus: string[][];
SystemStatus?: any;
Plugins: Plugins;
MemoryLimit: boolean;
SwapLimit: boolean;
KernelMemory: boolean;
CpuCfsPeriod: boolean;
CpuCfsQuota: boolean;
CPUShares: boolean;
CPUSet: boolean;
IPv4Forwarding: boolean;
BridgeNfIptables: boolean;
BridgeNfIp6tables: boolean;
Debug: boolean;
NFd: number;
OomKillDisable: boolean;
NGoroutines: number;
SystemTime: string;
LoggingDriver: string;
CgroupDriver: string;
NEventsListener: number;
KernelVersion: string;
OperatingSystem: string;
OSType: string;
Architecture: string;
IndexServerAddress: string;
RegistryConfig: RegistryConfig;
NCPU: number;
MemTotal: number;
GenericResources?: any;
DockerRootDir: string;
HttpProxy: string;
HttpsProxy: string;
NoProxy: string;
Name: string;
Labels: string[];
ExperimentalBuild: boolean;
ServerVersion: string;
ClusterStore: string;
ClusterAdvertise: string;
Runtimes: Runtimes;
DefaultRuntime: string;
Swarm: Swarm;
LiveRestoreEnabled: boolean;
Isolation: string;
InitBinary: string;
ContainerdCommit: ContainerdCommit;
RuncCommit: RuncCommit;
InitCommit: InitCommit;
SecurityOptions: string[];
ProductLicense: string;
Warnings?: any;
}
export class Platform {
Name: string;
}
export class Details {
ApiVersion: string;
Arch: string;
BuildTime: string;
Experimental: string;
GitCommit: string;
GoVersion: string;
KernelVersion: string;
MinAPIVersion: string;
Os: string;
}
export class Component {
Name: string;
Version: string;
Details: Details;
}
export class Version {
Platform: Platform;
Components: Component[];
Version: string;
ApiVersion: string;
MinAPIVersion: string;
GitCommit: string;
GoVersion: string;
Os: string;
Arch: string;
KernelVersion: string;
BuildTime: string;
}
}

View File

@ -0,0 +1,23 @@
import * as api from '../utils/api';
import * as opts from '../api/opts'
import * as types from '../api/types'
import * as http from 'http'
export namespace container {
export async function list(filters?: opts.container.ListOpts) {
return await api.get<types.container.Container[]>('/containers/json', filters)
}
export async function info(id: string, query: { size: boolean } = { size: false }) {
return await api.get<types.container.ContainerJSON>(`/containers/${id}/json`, query);
}
export async function logs(id: string, opts: opts.container.LogsOpts = {}): Promise<http.ServerResponse> {
return await api.stream(`/containers/${id}/logs`, Object.assign({
follow: true,
stdout: true,
stderr: true,
tail: 10
}, opts));
}
}

View File

@ -0,0 +1,6 @@
export * from './node'
export * from './swarm'
export * from './system'
export * from './network'
export * from './service'
export * from './container'

View File

@ -0,0 +1,9 @@
import * as api from '../utils/api'
import * as opts from '../api/opts'
import * as types from '../api/types'
export namespace network {
export async function list(opts?: opts.network.ListOpts) {
return await api.get<types.network.NetworkResource[]>('/networks', opts)
}
}

View File

@ -0,0 +1,8 @@
import * as api from '../utils/api'
import * as types from '../api/types'
export namespace node {
export async function list() {
return await api.get<types.node.Node[]>('/nodes');
}
}

View File

@ -0,0 +1,9 @@
import * as api from '../utils/api';
import * as opts from '../api/opts';
import * as types from '../api/types';
export namespace service {
export async function list(filters?: opts.service.ListOpts) {
return await api.get<types.service.Service[]>('/services', filters);
}
}

View File

@ -0,0 +1,13 @@
import * as api from '../utils/api'
import * as opts from '../api/opts'
import * as types from '../api/types'
export namespace swarm {
export async function inspect() {
return await api.get<types.swarm.Info>('/swarm');
}
export async function init(opts: opts.swarm.InitOpts) {
return await api.post<string>('/swarm/init', opts);
}
}

View File

@ -0,0 +1,22 @@
import * as api from '../utils/api'
import * as types from '../api/types'
export namespace system {
export async function info() {
return await api.get<types.system.Info>('/info');
}
export async function version() {
return await api.get<types.system.Version>('/version');
}
export async function events(cb: (events: object) => void) {
let stream = await api.stream<any>('/events');
stream.on('data', (chunk: ArrayBuffer) => {
cb(JSON.parse(Buffer.from(chunk).toString()))
})
stream.on('end', () => {
cb(undefined);
})
}
}

View File

@ -0,0 +1 @@
export * from './client'

View File

@ -0,0 +1,78 @@
import * as http from 'http'
import axios, { AxiosResponse, AxiosRequestConfig, Method, AxiosInstance } from 'axios'
let api: AxiosInstance;
export async function get<T>(path: string, data?: object): Promise<T> {
return await handle<T>("GET", path, { params: data });
}
export async function post<T>(path: string, data?: object): Promise<T> {
return await handle<T>("POST", path, { data });
}
export async function stream<T = http.ServerResponse>(path: string, data?: object): Promise<T> {
return await handle<T>("GET", path, { params: data, responseType: "stream" });
}
async function handle<T>(method: Method, path: string, reqConfig?: AxiosRequestConfig): Promise<T> {
let config: AxiosRequestConfig = {
method,
url: path,
};
let startTime = Date.now();
Object.assign(config, reqConfig)
let response: AxiosResponse;
try {
response = await api.request(config);
return response.data as T
} catch (ex) {
if (!ex.response) { throw ex; }
response = ex.response;
if (response.status > 299 && config.responseType == "stream") {
let stream = response.data;
response.data = await new Promise<T>((resolve, reject) => {
let cache = '';
stream.on('data', (chunk: ArrayBuffer) => {
cache += chunk.toString()
})
stream.on('end', () => {
resolve(JSON.parse(cache) as T);
})
})
}
throw new Error(JSON.stringify(response.data));
} finally {
if (response) {
console.log(`========== Docker API Invoke ==========
REQUEST METHOD : ${method}
REQUEST PATH : ${response.request.path}
REQUEST PARAMS : ${config.params ? JSON.stringify(config.params) : ''}
REQUEST BODY : ${config.data ? JSON.stringify(config.data) : ''}
RESPONSE BODY : ${toString.call(response.data.pipe) === "[object Function]" ? '<Stream>' : JSON.stringify(response.data)}
HANDLE TIME : ${Date.now() - startTime}ms
=======================================`);
}
// console.log(`${method} ${path} HTTP/1.1
// ${config.data ? JSON.stringify(config.data, null, 2) + '\n' : ''}
// HTTP/1.1 ${response.status} ${response.statusText}
// ${config.responseType != 'stream' ? JSON.stringify(response.data, null, 2) : config.responseType}`);
}
}
function init() {
const instanceConfig: AxiosRequestConfig = {
headers: {
'Content-Type': 'application/json'
},
timeout: 5000
}
if (process.env.DOCKER_HOST.startsWith("/")) {
instanceConfig.socketPath = process.env.DOCKER_HOST
} else {
instanceConfig.baseURL = process.env.DOCKER_HOST
}
api = axios.create(instanceConfig)
}
init();

View File

@ -0,0 +1,3 @@
export function Filters2String(filters: any) {
}

View File

@ -0,0 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": "src",
"outDir": "dist"
}
}

4
packages/faas/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/node_modules
/dist
/package-lock.json
/yarn.lock

22
packages/faas/.npmignore Normal file
View File

@ -0,0 +1,22 @@
src
test
typings
bundled
build
coverage
docs
wiki
gulpfile.js
bower.json
karma.conf.js
tsconfig.json
typings.json
CONTRIBUTING.md
ISSUE_TEMPLATE.md
PULL_REQUEST_TEMPLATE.md
tslint.json
wallaby.js
.travis.yml
.gitignore
.vscode
type_definitions

11
packages/faas/README.md Normal file
View File

@ -0,0 +1,11 @@
# `@dayu/faas`
> TODO: description
## Usage
```
const core = require('@dayu/faas');
// TODO: DEMONSTRATE API
```

View File

@ -0,0 +1,27 @@
{
"name": "@dayu/faas",
"version": "0.0.1",
"description": "> TODO: description",
"author": "MiaoWoo <admin@yumc.pw>",
"homepage": "https://github.com/circlecloud/dayu",
"license": "ISC",
"main": "dist/index.js",
"publishConfig": {
"registry": "https://repo.yumc.pw/repository/npm-hosted/"
},
"scripts": {
"dev": "npx ts-node-dev src/index.ts",
"clean": "rimraf dist",
"watch": "npx tsc --watch",
"build": "yarn clean && npx tsc",
"test": "echo \"Error: run tests from root\" && exit 1"
},
"dependencies": {
"axios": "^0.19.0"
},
"devDependencies": {
"rimraf": "^2.6.3",
"ts-node-dev": "^1.0.0-pre.40",
"typescript": "^3.5.2"
}
}

View File

@ -0,0 +1,28 @@
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/socket.io-client@2.2.0/dist/socket.io.js"> </script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@3.12.2/dist/xterm.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@3.12.2/dist/addons/fullscreen/fullscreen.css">
<script src="https://cdn.jsdelivr.net/npm/xterm@3.12.2/dist/xterm.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xterm@3.12.2/dist/addons/fit/fit.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xterm@3.12.2/dist/addons/attach/attach.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xterm@3.12.2/dist/addons/fullscreen/fullscreen.js"></script>
<style>
#terminal-container .terminal.xterm {
height: 100%;
}
#terminal-container .xterm-viewport {
height: 100% !important;
}
</style>
</head>
<body>
<div id="terminal" style="height: 100%;"></div>
<script type="text/javascript" src="js/index.js"></script>
</body>
</html>

View File

@ -0,0 +1,68 @@
let command = '';
Terminal.applyAddon(fit);
Terminal.applyAddon(attach);
Terminal.applyAddon(fullscreen);
var term = new Terminal({
experimentalCharAtlas: 'dynamic',
cursorBlink: false,
});
term.open(document.getElementById('terminal'));
term.toggleFullScreen();
term.fit();
window.onresize = function() {
term.fit();
}
let query = {}
location.search.substring(1).split("&").forEach(q => {
let qy = q.split("=", 2);
query[qy[0]] = qy[1]
})
console.log(query);
var socket = io('/container', {
path: '/ws',
transports: ['websocket']
});
socket.on('connect', () => {
term.writeln('connect')
if (query.action) {
term.writeln(`Recover Action: ${query.action} Data: ${query.data}`)
switch (query.action) {
case "container":
socket.emit('logs', {
id: query.data,
since: Date.now() / 1000 - 60 * 15,
until: Date.now() / 1000,
stderr: false,
tail: "all"
})
break;
default:
}
}
});
term.on('data', async data => {
if (data == '\t') {
return;
}
term.write(data);
if (data == '\r') {
term.write('\n');
socket.emit('logs', {
id: command
})
command = '';
} else {
command += data;
}
});
socket.on('message', data => {
term.write(data.toString() + '\r\n');
});
socket.on('disconnect', () => {
term.reset();
term.writeln('disconnect');
});

26
packages/faas/src/api.ts Normal file
View File

@ -0,0 +1,26 @@
import * as faas from './interfaces'
import axios, { AxiosRequestConfig } from 'axios'
const instanceConfig: AxiosRequestConfig = {
baseURL: 'https://faas.yumc.pw',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic YWRtaW46MmQ2MzdiYzQ4MWQxYThhMjg2M2E2ZTIzOTY1ZWRlNDI0ZTRjMTk2OTQyMzU5N2M5MzRlNGQyY2FlZTNkMjk2OA=='
},
timeout: 5000
}
let api = axios.create(instanceConfig)
async function get<T>(path: string) {
let result = await api.get(path);
return result.data as T;
}
export async function getFunctions() {
return await get<faas.Function[]>('/system/functions');
}
export async function getFunction(name: string) {
return await get<faas.Function>(`/system/function/${name}`);
}

View File

@ -0,0 +1 @@
export * from './api'

View File

@ -0,0 +1,13 @@
export interface Labels {
[key: string]: string
}
export interface Function {
name: string;
image: string;
invocationCount: number;
replicas: number;
envProcess: string;
availableReplicas: number;
labels: Labels;
annotations?: any;
}

View File

@ -0,0 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": "src",
"outDir": "dist"
}
}

4
packages/vscode/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
out
node_modules
.vscode-test/
*.vsix

View File

@ -0,0 +1,7 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"ms-vscode.vscode-typescript-tslint-plugin"
]
}

35
packages/vscode/.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,35 @@
// A launch configuration that compiles the extension and then opens it inside a new window
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
{
"version": "0.2.0",
"configurations": [{
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/out/**/*.js"
],
"preLaunchTask": "npm: watch"
},
{
"name": "Extension Tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test"
],
"outFiles": [
"${workspaceFolder}/out/test/**/*.js"
],
"preLaunchTask": "npm: watch"
}
]
}

12
packages/vscode/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,12 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.exclude": {
"out": false // set this to true to hide the "out" folder with the compiled JS files
},
"search.exclude": {
"out": true // set this to false to include "out" folder in search results
},
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
"typescript.tsc.autoDetect": "off",
"typescript.tsdk": "node_modules/typescript/lib"
}

20
packages/vscode/.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,20 @@
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "watch",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"presentation": {
"reveal": "never"
},
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

View File

@ -0,0 +1,10 @@
.vscode/**
.vscode-test/**
out/test/**
src/**
.gitignore
vsc-extension-quickstart.md
**/tsconfig.json
**/tslint.json
**/*.map
**/*.ts

View File

@ -0,0 +1,9 @@
# Change Log
All notable changes to the "faas" extension will be documented in this file.
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
## [Unreleased]
- Initial release

65
packages/vscode/README.md Normal file
View File

@ -0,0 +1,65 @@
# faas README
This is the README for your extension "faas". After writing up a brief description, we recommend including the following sections.
## Features
Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file.
For example if there is an image subfolder under your extension project workspace:
\!\[feature X\]\(images/feature-x.png\)
> Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow.
## Requirements
If you have any requirements or dependencies, add a section describing those and how to install and configure them.
## Extension Settings
Include if your extension adds any VS Code settings through the `contributes.configuration` extension point.
For example:
This extension contributes the following settings:
* `myExtension.enable`: enable/disable this extension
* `myExtension.thing`: set to `blah` to do something
## Known Issues
Calling out known issues can help limit users opening duplicate issues against your extension.
## Release Notes
Users appreciate release notes as you update your extension.
### 1.0.0
Initial release of ...
### 1.0.1
Fixed issue #.
### 1.1.0
Added features X, Y, and Z.
-----------------------------------------------------------------------------------------------------------
## Working with Markdown
**Note:** You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts:
* Split the editor (`Cmd+\` on macOS or `Ctrl+\` on Windows and Linux)
* Toggle preview (`Shift+CMD+V` on macOS or `Shift+Ctrl+V` on Windows and Linux)
* Press `Ctrl+Space` (Windows, Linux) or `Cmd+Space` (macOS) to see a list of Markdown snippets
### For more information
* [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown)
* [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/)
**Enjoy!**

View File

@ -0,0 +1,76 @@
{
"name": "@dayu/vscode",
"displayName": "vscode",
"description": "",
"version": "0.0.1",
"engines": {
"vscode": "^1.35.0"
},
"categories": [
"Other"
],
"activationEvents": [
"onCommand:extension.helloWorld"
],
"main": "./dist/extension.js",
"contributes": {
"viewsContainers": {
"activitybar": [
{
"id": "dayu-explorer",
"title": "Dayu Explorer",
"icon": "src/images/logo.svg"
}
]
},
"views": {
"dayu-explorer": [
{
"id": "docker-explorer",
"name": "Docker"
},
{
"id": "openfaas-explorer",
"name": "OpenFaaS"
}
]
},
"commands": [
{
"command": "dayu.container.logs",
"title": "View Container Logs",
"icon": {
"dark": "src/images/browser.svg"
}
}
],
"menus": {
"view/item/context": [
{
"command": "dayu.container.logs",
"when": "view == docker-explorer && viewItem =~ /.*\"type\":\"CONTAINER\".*/",
"group": "inline"
}
]
}
},
"scripts": {
"vscode:prepublish": "yarn run compile",
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./",
"postinstall": "node ../../node_modules/vscode/bin/install",
"test": "yarn run compile && node ./node_modules/vscode/bin/test"
},
"dependencies": {
"@dayu/docker-api": "^0.0.1",
"@dayu/faas": "^0.0.1",
"axios": "^0.19.0"
},
"devDependencies": {
"@types/mocha": "^2.2.42",
"@types/node": "^10.12.21",
"tslint": "^5.12.1",
"typescript": "^3.3.1",
"vscode": "^1.1.28"
}
}

View File

@ -0,0 +1,15 @@
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';
process.env.DOCKER_HOST = '/var/run/docker.sock'
import { OpenFaasProvider, DockerProvider } from './provider'
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {
new DockerProvider(context);
new OpenFaasProvider(context);
}
// this method is called when your extension is deactivated
export function deactivate() { }

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16.08108103275299" height="16.540540516376495" style=""><rect id="backgroundrect" width="100%" height="100%" x="0" y="0" fill="none" stroke="none" style="" class=""/><g class="currentLayer" style=""><title>Layer 1</title><path d="M11.542335271835327,3.076456665992737 H3.147498369216919 C2.6127313375473022,3.076456665992737 2.178863525390625,3.526281714439392 2.178863525390625,4.080699563026428 v7.364412307739258 c0,0.5544231534004211 0.4338677227497101,1.0042381286621094 0.9686350226402283,1.0042381286621094 h8.394837379455566 c0.534767210483551,0 0.9686350226402283,-0.44981494545936584 0.9686350226402283,-1.0042381286621094 V4.080699563026428 c0,-0.5544231534004211 -0.4338677227497101,-1.0042381286621094 -0.9686350226402283,-1.0042381286621094 zM2.824620246887207,4.080699563026428 c0,-0.18411031365394592 0.14529526233673096,-0.33474603295326233 0.322878360748291,-0.33474603295326233 h0.9686350226402283 v1.3389841318130493 H2.824620246887207 V4.080699563026428 zm9.040594100952148,7.364412307739258 c0,0.18411031365394592 -0.14529526233673096,0.33474603295326233 -0.322878360748291,0.33474603295326233 H3.147498369216919 c-0.17758308351039886,0 -0.322878360748291,-0.1506357043981552 -0.322878360748291,-0.33474603295326233 V5.754433751106262 h9.040594100952148 v5.690682888031006 zm0,-6.360174655914307 H4.761890172958374 V3.745947003364563 h6.780445098876953 c0.17758308351039886,0 0.322878360748291,0.1506357043981552 0.322878360748291,0.33474603295326233 v1.0042381286621094 z" id="svg_1" class="selected" transform="translate(0.540541, 0.27027)" fill="#ffffff" fill-opacity="1"/></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><path fill="#FFF" d="M75.438 39.65L65.295 29.504V14.53H50.738L40.77 4.56 40.21 4 29.68 14.53H14.53v15.15L4 40.21l10.53 10.53v14.555h14.975L39.65 75.44l.56.56 10.706-10.705h14.38v-14.38L75.44 40.772l.56-.56-.562-.56zm-11.73-23.534v11.802l-3.983-3.983-.562-.562-.562.562-12.815 12.817h-2.713v-1.94l13.412-13.415.562-.562-.562-.562-4.157-4.16h11.38v.003zm0 14.047v6.59h-15.68l11.135-11.135 4.544 4.545zM42.887 40.77l.712.714h-2.115V43.6l-1.273-1.273-1.87 1.87v-2.712h-1.94l1.273-1.273-1.87-1.87h2.537v-2.538l1.31 1.31.56.562.563-.56.713-.714v1.94H44.2l-1.308 1.31-.562.562.56.557zm11.915-19.934l-11.73 11.73v-16.45h7.01l4.72 4.72zM40.21 6.246l8.284 8.283h-7.01v19.624l-1.274 1.274-1.87-1.87v-19.03h-6.414l8.284-8.283zm-9.872 9.87h6.414V31.97L25.62 20.836l4.718-4.72zm-14.22 0h11.976l-4.72 4.72.56.563 12.818 12.816v2.537h-2.538l-13.378-13.38-4.72 4.72V16.118zm0 14.222l4.72-4.72L31.97 36.752H16.117v-6.414zm-1.59 18.157L6.246 40.21l8.285-8.285v6.414h19.028l1.87 1.87-1.273 1.272H14.53v7.013zm1.588-5.423h16.45l-11.73 11.73-4.72-4.722v-7.008zm0 20.635v-11.38l4.16 4.16.562.56.56-.56L34.814 43.07h1.94v2.713L23.935 58.602l-.56.562.56.562 3.983 3.98h-11.8zm9.503-4.544L36.752 48.03v15.677h-6.59l-4.544-4.544zm14.59 14.592l-8.46-8.46h6.59V46.44l1.87-1.868 1.274 1.272v19.45h7.186l-8.46 8.46zm10.048-10.048h-7.186V47.434l11.73 11.73-4.544 4.543zm13.45 0H52.502l4.544-4.543-.562-.562-13.413-13.414v-2.115h2.115L58.6 56.487l.562.562 4.545-4.546v11.203zm0-13.45l-4.545 4.546-11.73-11.73h16.274v7.185zm1.587-1.587v-7.186h-19.45l-1.272-1.273 1.87-1.87h18.854v-6.59l8.46 8.46-8.462 8.46z"/></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" height="512" viewBox="0 0 1489 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M1465.995636 345.832727c-57.064727-38.818909-123.904-39.656727-168.122181-34.164363-21.876364-92.066909-105.192727-144.197818-109.288728-146.711273l-31.464727-19.269818-22.528 29.323636c-71.121455 92.718545-52.317091 193.629091-22.248727 255.720727a185.250909 185.250909 0 0 1-75.031273 20.48h-25.227636V298.449455h-172.218182V0.186182H632.087273v149.131636H291.374545v149.038546h-170.356363v152.855272H9.588364l-5.213091 35.002182c-1.210182 7.912727-27.927273 195.304727 96.628363 340.433455 91.136 106.123636 236.730182 159.930182 432.779637 159.930182 302.824727 0 488.913455-133.678545 591.592727-245.76a769.675636 769.675636 0 0 0 141.312-218.577455c189.719273-3.258182 215.505455-129.210182 216.529455-134.888727l4.933818-26.437818-22.248728-15.080728zM691.665455 297.797818v-88.715636h88.622545v88.715636H691.665455zM350.952727 446.836364v-88.715637h88.529455V446.836364H350.952727z m170.356364 0v-88.715637h88.529454V446.836364h-88.436363z m170.356364 0v-88.715637h88.622545V446.836364H691.665455z m172.218181-88.715637h88.436364V446.836364h-88.436364v-88.715637zM691.665455 60.043636h88.622545v88.622546H691.665455V60.043636zM521.309091 209.082182h88.529454v88.715636h-88.436363v-88.715636z m-170.356364 0h88.529455v88.715636H350.952727v-88.715636zM180.596364 358.120727h88.436363V446.836364h-88.436363v-88.715637z m353.28 546.257455c-93.090909 0-172.404364-13.125818-237.474909-39.098182 48.221091-10.24 103.237818-29.044364 152.66909-63.953455a41.146182 41.146182 0 0 0-47.19709-67.211636c-80.430545 56.692364-184.32 60.602182-218.298182 60.229818a301.614545 301.614545 0 0 1-19.642182-20.666182C92.439273 690.734545 82.850909 586.752 83.502545 533.410909h953.809455c3.537455 0 89.088-0.744727 156.858182-59.857454l5.026909-4.468364c-7.819636 22.993455-155.927273 435.2-665.320727 435.2z m706.746181-464.802909l-25.413818-1.210182-15.266909-20.386909c-0.558545-0.837818-54.644364-74.565818-21.876363-155.461818 20.945455 21.690182 44.125091 55.389091 42.914909 97.093818l-1.675637 58.274909 55.389091-17.966546c0.651636-0.186182 58.833455-17.966545 112.267637-1.582545-18.897455 20.573091-60.043636 45.428364-146.33891 41.239273zM551.284364 606.580364a67.118545 67.118545 0 0 1 0 134.237091 67.118545 67.118545 0 0 1 0-134.237091z m0 82.292363a15.080727 15.080727 0 1 0 0-30.254545 15.080727 15.080727 0 0 0 0 30.254545z" fill="#FFFFFF" /></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><path fill="#FFF" d="M14.752 32.456l-7.72.002v7.553h7.72v-7.554zm9.65 0h-7.72v7.556h7.72v-7.556zm0-9.445h-7.72v7.556h7.72V23.01zm9.65 9.446h-7.72v7.556h7.72v-7.556zm0-9.445h-7.72v7.556h7.72V23.01zm9.648 9.446h-7.72v7.556h7.72v-7.556zm0-9.445h-7.72v7.556h7.72V23.01zm9.65 9.446l-7.72.002v7.553h7.72v-7.554zm-9.65-18.89h-7.72v7.556h7.72v-7.556zm31.938 23.106c-2.51-1.417-5.85-1.61-8.693-.792-.35-2.958-2.337-5.55-4.7-7.41l-.938-.738-.79.89c-1.58 1.79-2.052 4.768-1.838 7.053.16 1.68.697 3.388 1.756 4.737-.805.473-1.717.85-2.53 1.12-1.657.55-3.456.854-5.206.854H3.544l-.105 1.107c-.354 3.7.165 7.402 1.728 10.778l.673 1.343.078.124c4.622 7.68 12.74 10.914 21.584 10.914 17.125 0 31.248-7.48 37.734-23.284 4.335.222 8.77-1.033 10.89-5.082l.54-1.033-1.028-.578zm-57.77 19.982v.002c-2.18 0-3.955-1.735-3.955-3.866 0-2.132 1.774-3.866 3.954-3.866s3.954 1.732 3.954 3.865c0 2.13-1.77 3.864-3.95 3.864zm-.01-5.854c-1.137 0-2.06.9-2.06 2.013 0 1.11.924 2.01 2.06 2.01 1.134 0 2.057-.9 2.057-2.01 0-1.11-.922-2.013-2.057-2.013z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="25pt" height="25pt" viewBox="0 0 25 25" version="1.1">
<g id="surface1">
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 14.398438 21.09375 C 14.113281 20.417969 13.78125 19.636719 13.496094 18.886719 C 12.792969 17.039062 15.523438 16.753906 15.523438 16.753906 C 15.523438 16.753906 21.378906 16.457031 21.722656 9.683594 C 21.722656 9.683594 19.847656 11.589844 18.210938 11.351562 C 16.574219 11.113281 14.234375 10 12.34375 13.421875 C 10.4375 10 8.109375 11.125 6.472656 11.351562 C 4.835938 11.589844 2.960938 9.683594 2.960938 9.683594 C 3.304688 16.46875 9.160156 16.753906 9.160156 16.753906 C 9.160156 16.753906 11.683594 17.039062 11.1875 18.886719 C 10.992188 19.625 10.757812 20.351562 10.480469 21.0625 L 10.992188 21.996094 L 11.683594 22.535156 L 12.34375 22.714844 L 12.777344 22.714844 L 13.605469 22.097656 L 14.203125 21.289062 Z M 14.398438 21.09375 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 18.167969 11.351562 C 16.53125 11.109375 14.1875 10 12.296875 13.421875 C 12.066406 12.980469 11.777344 12.574219 11.441406 12.207031 C 11.546875 14.699219 11.964844 20.328125 13.453125 22.191406 L 13.542969 22.117188 L 14.140625 21.304688 L 14.351562 21.09375 C 14.066406 20.417969 13.738281 19.636719 13.453125 18.886719 C 12.746094 17.042969 15.480469 16.757812 15.480469 16.757812 C 15.480469 16.757812 21.332031 16.457031 21.679688 9.683594 C 21.679688 9.671875 19.816406 11.578125 18.167969 11.351562 Z M 18.167969 11.351562 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 14.398438 21.519531 C 14.226562 21.519531 14.066406 21.417969 13.996094 21.257812 C 13.707031 20.609375 13.394531 19.835938 13.085938 19.027344 C 12.863281 18.527344 12.894531 17.953125 13.171875 17.480469 C 13.765625 16.507812 15.304688 16.320312 15.480469 16.300781 C 15.710938 16.289062 20.359375 15.980469 21.175781 10.710938 C 20.414062 11.277344 19.257812 11.933594 18.148438 11.769531 C 17.898438 11.738281 17.640625 11.683594 17.367188 11.628906 C 15.8125 11.308594 14.199219 10.976562 12.730469 13.617188 C 12.683594 13.699219 12.609375 13.769531 12.523438 13.808594 C 12.464844 13.835938 12.402344 13.847656 12.339844 13.847656 C 12.179688 13.847656 12.03125 13.757812 11.953125 13.617188 C 10.480469 10.976562 8.871094 11.308594 7.3125 11.628906 C 7.042969 11.683594 6.785156 11.738281 6.53125 11.773438 C 5.421875 11.933594 4.265625 11.277344 3.503906 10.710938 C 4.324219 15.980469 8.972656 16.289062 9.179688 16.300781 C 9.191406 16.300781 9.199219 16.300781 9.207031 16.304688 C 9.269531 16.308594 10.746094 16.488281 11.390625 17.433594 C 11.691406 17.890625 11.773438 18.460938 11.609375 18.984375 C 11.410156 19.738281 11.171875 20.480469 10.890625 21.210938 C 10.800781 21.433594 10.542969 21.546875 10.316406 21.457031 C 10.09375 21.367188 9.980469 21.113281 10.070312 20.886719 C 10.339844 20.191406 10.570312 19.480469 10.761719 18.757812 C 10.855469 18.480469 10.820312 18.175781 10.664062 17.925781 C 10.265625 17.34375 9.207031 17.1875 9.117188 17.175781 C 8.707031 17.148438 2.871094 16.578125 2.519531 9.691406 C 2.507812 9.507812 2.613281 9.339844 2.78125 9.265625 C 2.949219 9.191406 3.144531 9.230469 3.269531 9.359375 C 3.75 9.84375 5.25 11.070312 6.40625 10.898438 C 6.636719 10.867188 6.878906 10.816406 7.136719 10.765625 C 8.628906 10.460938 10.632812 10.046875 12.339844 12.566406 C 14.050781 10.046875 16.054688 10.460938 17.546875 10.765625 C 17.804688 10.816406 18.046875 10.867188 18.269531 10.898438 C 19.4375 11.070312 20.933594 9.847656 21.410156 9.359375 C 21.539062 9.230469 21.734375 9.191406 21.902344 9.265625 C 22.066406 9.339844 22.171875 9.507812 22.164062 9.691406 C 21.8125 16.597656 15.941406 17.148438 15.5625 17.175781 C 15.207031 17.21875 14.230469 17.429688 13.917969 17.941406 C 13.789062 18.183594 13.785156 18.46875 13.90625 18.714844 C 14.210938 19.507812 14.519531 20.265625 14.800781 20.898438 C 14.859375 21.035156 14.847656 21.195312 14.765625 21.316406 C 14.683594 21.441406 14.546875 21.519531 14.398438 21.519531 Z M 14.398438 21.519531 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 0.585938 22.234375 C 0.585938 22.234375 3.0625 21.0625 5.242188 19.804688 C 5.34375 19.742188 6.695312 19.804688 6.695312 19.804688 L 7.882812 19.804688 C 7.988281 19.804688 9.546875 20.75 9.546875 20.75 C 9.546875 20.75 11.171875 21.5 11.453125 21.574219 C 11.738281 21.648438 14.203125 21.304688 14.203125 21.304688 L 16.019531 20.285156 L 17.460938 19.804688 L 20.28125 20.285156 C 20.28125 20.285156 26.648438 21.8125 24.15625 22.683594 C 24.003906 22.730469 22.863281 24.019531 22.730469 24.125 C 22.609375 24.230469 18.960938 25.085938 18.960938 25.085938 L 11.621094 25.085938 L 2.539062 24.382812 Z M 0.585938 22.234375 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 24.324219 22.132812 C 22.722656 22.132812 21.882812 21.59375 21.140625 21.121094 C 20.441406 20.667969 19.78125 20.242188 18.4375 20.242188 C 17.09375 20.242188 16.433594 20.667969 15.734375 21.121094 C 14.992188 21.59375 14.152344 22.132812 12.550781 22.132812 C 10.953125 22.132812 10.113281 21.59375 9.371094 21.121094 C 8.671875 20.667969 8.011719 20.242188 6.667969 20.242188 C 5.324219 20.242188 4.664062 20.667969 3.960938 21.121094 C 3.222656 21.597656 2.382812 22.132812 0.78125 22.132812 C 0.539062 22.132812 0.34375 21.9375 0.34375 21.695312 C 0.34375 21.453125 0.539062 21.253906 0.78125 21.253906 C 2.125 21.253906 2.785156 20.828125 3.488281 20.378906 C 4.226562 19.902344 5.066406 19.363281 6.667969 19.363281 C 8.269531 19.363281 9.105469 19.902344 9.847656 20.378906 C 10.546875 20.828125 11.210938 21.253906 12.550781 21.253906 C 13.894531 21.253906 14.558594 20.828125 15.257812 20.378906 C 15.996094 19.902344 16.835938 19.363281 18.4375 19.363281 C 20.039062 19.363281 20.878906 19.902344 21.617188 20.378906 C 22.320312 20.828125 22.980469 21.253906 24.324219 21.253906 C 24.566406 21.253906 24.761719 21.453125 24.761719 21.695312 C 24.761719 21.9375 24.566406 22.132812 24.324219 22.132812 Z M 24.324219 22.132812 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 9.402344 4.65625 L 8.6875 9.289062 L 13.808594 10.082031 L 14.523438 5.449219 Z M 10.539062 8.199219 L 10.089844 8.136719 L 10.328125 6.367188 L 10.78125 6.425781 Z M 11.621094 8.332031 L 11.171875 8.273438 L 11.410156 6.515625 L 11.859375 6.578125 Z M 12.6875 8.484375 L 12.238281 8.421875 L 12.476562 6.664062 L 12.925781 6.726562 Z M 12.6875 8.484375 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 4.21875 4.515625 L 5.574219 9 L 9.964844 7.675781 L 10.195312 6.386719 L 9.179688 3.019531 Z M 6.773438 7.21875 L 6.339844 7.359375 L 5.792969 5.65625 L 6.226562 5.515625 Z M 7.808594 6.875 L 7.375 7.011719 L 6.832031 5.324219 L 7.265625 5.1875 Z M 8.832031 6.550781 L 8.402344 6.6875 L 7.859375 5 L 8.292969 4.863281 Z M 8.832031 6.550781 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 20.164062 3.867188 L 14.996094 4.234375 L 15.324219 8.90625 L 20.492188 8.542969 Z M 16.484375 7.339844 L 16.394531 5.566406 L 16.847656 5.542969 L 16.9375 7.316406 Z M 17.578125 7.28125 L 17.476562 5.507812 L 17.925781 5.484375 L 18.03125 7.253906 Z M 18.660156 7.222656 L 18.554688 5.449219 L 19.007812 5.421875 L 19.113281 7.195312 Z M 18.660156 7.222656 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 20.613281 0 L 4.503906 0 C 2.019531 0.00390625 0.00390625 2.019531 0 4.503906 L 0 20.613281 C 0.00390625 23.101562 2.019531 25.117188 4.503906 25.117188 L 20.613281 25.117188 C 23.101562 25.117188 25.113281 23.101562 25.117188 20.613281 L 25.117188 4.503906 C 25.113281 2.019531 23.101562 0.00390625 20.613281 0 Z M 24.304688 20.613281 C 24.304688 22.652344 22.652344 24.304688 20.613281 24.304688 L 4.503906 24.304688 C 2.464844 24.304688 0.816406 22.652344 0.8125 20.613281 L 0.8125 4.503906 C 0.816406 2.464844 2.464844 0.816406 4.503906 0.8125 L 20.613281 0.8125 C 22.652344 0.816406 24.304688 2.464844 24.304688 4.503906 Z M 24.304688 20.613281 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 5.445312 4.863281 L 9.242188 4.863281 L 9.242188 7.460938 L 5.445312 7.460938 Z M 5.445312 4.863281 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 9.613281 5.769531 L 13.285156 5.769531 L 13.285156 8.824219 L 9.613281 8.824219 Z M 9.613281 5.769531 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 15.71875 5.027344 L 19.71875 5.027344 L 19.71875 7.75 L 15.71875 7.75 Z M 15.71875 5.027344 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M13.451 5.609l-.579-.939-1.068.812-.076.094c-.335.415-.927 1.341-1.124 2.876l-.021.165.033.163.071.345c0 1.654-1.346 3-3 3-.795 0-1.545-.311-2.107-.868-.563-.567-.873-1.317-.873-2.111 0-1.431 1.007-2.632 2.351-2.929v2.926s2.528-2.087 2.984-2.461h.012l3.061-2.582-4.919-4.1h-1.137v2.404c-3.429.318-6.121 3.211-6.121 6.721 0 1.809.707 3.508 1.986 4.782 1.277 1.282 2.976 1.988 4.784 1.988 3.722 0 6.75-3.028 6.75-6.75 0-1.245-.349-2.468-1.007-3.536z" fill="#2D2D30"/><path d="M12.6 6.134l-.094.071c-.269.333-.746 1.096-.91 2.375.057.277.092.495.092.545 0 2.206-1.794 4-4 4-1.098 0-2.093-.445-2.817-1.164-.718-.724-1.163-1.718-1.163-2.815 0-2.206 1.794-4 4-4l.351.025v1.85s1.626-1.342 1.631-1.339l1.869-1.577-3.5-2.917v2.218l-.371-.03c-3.176 0-5.75 2.574-5.75 5.75 0 1.593.648 3.034 1.695 4.076 1.042 1.046 2.482 1.694 4.076 1.694 3.176 0 5.75-2.574 5.75-5.75-.001-1.106-.318-2.135-.859-3.012z" fill="#C5C5C5"/></svg>

After

Width:  |  Height:  |  Size: 986 B

View File

@ -0,0 +1,28 @@
import * as vscode from 'vscode'
export class CteateItemOpt {
label: string;
context?: ItemContextValue;
state?: vscode.TreeItemCollapsibleState = vscode.TreeItemCollapsibleState.None;
icon?: string;
tooltip?: string;
}
export interface ItemContextValue {
type?: string;
data?: any;
}
export abstract class BaseProvider<T> implements vscode.TreeDataProvider<T> {
abstract onDidChangeTreeData?: vscode.Event<T | null | undefined> | undefined;
abstract getTreeItem(element: T): vscode.TreeItem | Thenable<vscode.TreeItem>;
abstract getChildren(element?: T | undefined): vscode.ProviderResult<T[]>;
createTreeItem(opts: CteateItemOpt) {
let item = new vscode.TreeItem(opts.label, opts.state);
item.contextValue = JSON.stringify(opts.context);
if (opts.icon) { item.iconPath = `src/images/${opts.icon}.svg` }
if (opts.tooltip) { item.tooltip = opts.tooltip; }
return item;
}
}

View File

@ -0,0 +1,127 @@
import * as vscode from 'vscode'
import { BaseProvider, ItemContextValue } from './base'
import * as docker from '@dayu/docker-api'
enum Type {
ROOT = "ROOT",
HOST = "HOST",
CONTAINERS = "CONTAINERS",
CONTAINER = "CONTAINER",
SERVICES = "SERVICES",
SERVICE = "SERVICE",
NETWORKS = "NETWORKS",
NETWORK = "NETWORK",
STACKS = "STACKS",
STACK = "STACK",
NODES = "NODES",
NODE = "NODE"
}
let TREE_LIST = [Type.NODES, Type.CONTAINERS, Type.SERVICES, Type.NETWORKS]
export class DockerProvider extends BaseProvider<vscode.TreeItem> {
onDidChangeTreeData?: vscode.Event<vscode.TreeItem | null | undefined> | undefined;
constructor(context: vscode.ExtensionContext) {
super();
context.subscriptions.push(
vscode.commands.registerCommand('dayu.container.logs', (item: vscode.TreeItem) => {
let value: ItemContextValue = JSON.parse(item.contextValue);
let url = `https://faas.n.yumc.pw?action=container&data=${value.data.id}`;
return vscode.commands.executeCommand("mini-browser.openUrl", url);
}),
vscode.window.registerTreeDataProvider('docker-explorer', this)
)
}
getTreeItem(element: vscode.TreeItem): vscode.TreeItem | Thenable<vscode.TreeItem> {
return element;
}
async getChildren(element?: vscode.TreeItem | undefined): Promise<vscode.TreeItem[]> {
if (!element || !element.contextValue) {
return [this.createTreeItem({
label: 'Docker',
context: {
type: Type.ROOT
},
state: vscode.TreeItemCollapsibleState.Collapsed,
icon: "docker"
})]
}
let value: ItemContextValue = JSON.parse(element.contextValue);
switch (value.type) {
case Type.ROOT:
return TREE_LIST.map(i => {
return this.createTreeItem({
label: i,
context: {
type: i
},
state: vscode.TreeItemCollapsibleState.Collapsed
})
})
case Type.NODES:
let nodes = await docker.node.list();
return nodes.map(n => {
return this.createTreeItem({
label: n.ID,
context: {
type: Type.NODE,
data: {
id: n.ID
}
},
tooltip: JSON.stringify(n, undefined, 2)
})
})
case Type.CONTAINERS:
let containers = await docker.container.list();
return containers.map(c => {
return this.createTreeItem({
label: c.Names[0],
context: {
type: Type.CONTAINER,
data: {
id: c.Id
}
},
tooltip: JSON.stringify(c, undefined, 2)
})
})
case Type.SERVICES:
let services = await docker.service.list();
return services.map(s => {
return this.createTreeItem({
label: s.Spec.Name,
context: {
type: Type.SERVICE,
data: {
id: s.ID
}
},
tooltip: JSON.stringify(s, undefined, 2)
})
})
case Type.NETWORKS:
let networks = await docker.network.list();
return networks.map(n => {
return this.createTreeItem({
label: n.Name,
context: {
type: Type.NETWORK,
data: {
id: n.Id
}
},
tooltip: JSON.stringify(n, undefined, 2)
})
})
case Type.CONTAINER:
break;
default:
}
return [];
}
}

View File

@ -0,0 +1,48 @@
import * as vscode from 'vscode'
import * as faas from '@dayu/faas'
import { BaseProvider, ItemContextValue } from './base'
enum Type {
ROOT = "ROOT",
}
export class OpenFaasProvider extends BaseProvider<vscode.TreeItem> {
onDidChangeTreeData?: vscode.Event<vscode.TreeItem>;
constructor(context: vscode.ExtensionContext) {
super()
context.subscriptions.push(
vscode.window.registerTreeDataProvider('openfaas-explorer', this)
)
}
getTreeItem(element: vscode.TreeItem): vscode.TreeItem | Promise<vscode.TreeItem> {
return element;
}
async getChildren(element?: vscode.TreeItem): Promise<vscode.TreeItem[]> {
if (!element || !element.contextValue) {
return [this.createTreeItem({
label: "OpenFaaS",
state: vscode.TreeItemCollapsibleState.Collapsed,
context: {
type: Type.ROOT
},
icon: "logo"
})]
}
let value: ItemContextValue = JSON.parse(element.contextValue);
switch (value.type) {
case Type.ROOT:
let funcs = await faas.getFunctions();
return funcs.map(f => {
return this.createTreeItem({
label: f.name,
tooltip: JSON.stringify(f, undefined, 2)
})
});
default:
return [];
}
}
}

View File

@ -0,0 +1,2 @@
export * from './faas'
export * from './docker'

View File

@ -0,0 +1,22 @@
//
// Note: This example test is leveraging the Mocha test framework.
// Please refer to their documentation on https://mochajs.org/ for help.
//
// The module 'assert' provides assertion methods from node
import * as assert from 'assert';
// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
// import * as vscode from 'vscode';
// import * as myExtension from '../extension';
// Defines a Mocha test suite to group tests of similar kind together
suite("Extension Tests", function () {
// Defines a Mocha unit test
test("Something 1", function() {
assert.equal(-1, [1, 2, 3].indexOf(5));
assert.equal(-1, [1, 2, 3].indexOf(0));
});
});

View File

@ -0,0 +1,23 @@
//
// PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING
//
// This file is providing the test runner to use when running extension tests.
// By default the test runner in use is Mocha based.
//
// You can provide your own test runner if you want to override it by exporting
// a function run(testsRoot: string, clb: (error: Error, failures?: number) => void): void
// that the extension host can call to run the tests. The test runner is expected to use console.log
// to report the results back to the caller. When the tests are finished, return
// a possible error to the callback or null if none.
import * as testRunner from 'vscode/lib/testrunner';
// You can directly control Mocha options by configuring the test runner below
// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options
// for more info
testRunner.configure({
ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.)
useColors: true // colored output from test results
});
module.exports = testRunner;

View File

@ -0,0 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": "src",
"outDir": "dist"
}
}

View File

@ -0,0 +1,41 @@
# Welcome to your VS Code Extension
## What's in the folder
* This folder contains all of the files necessary for your extension.
* `package.json` - this is the manifest file in which you declare your extension and command.
* The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesnt yet need to load the plugin.
* `src/extension.ts` - this is the main file where you will provide the implementation of your command.
* The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`.
* We pass the function containing the implementation of the command as the second parameter to `registerCommand`.
## Get up and running straight away
* Press `F5` to open a new window with your extension loaded.
* Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`.
* Set breakpoints in your code inside `src/extension.ts` to debug your extension.
* Find output from your extension in the debug console.
## Make changes
* You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`.
* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes.
## Explore the API
* You can open the full set of our API when you open the file `node_modules/vscode/vscode.d.ts`.
## Run tests
* Open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Extension Tests`.
* Press `F5` to run the tests in a new window with your extension loaded.
* See the output of the test result in the debug console.
* Make changes to `test/extension.test.ts` or create new test files inside the `test` folder.
* By convention, the test runner will only consider files matching the name pattern `**.test.ts`.
* You can create folders inside the `test` folder to structure your tests any way you want.
## Go further
* Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/testing-extension).
* [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VSCode extension marketplace.
* Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration).

14
tsconfig.json Normal file
View File

@ -0,0 +1,14 @@
{
"compilerOptions": {
"baseUrl": "src",
"outDir": "dist",
"target": "es6",
"module": "commonjs",
"sourceMap": true,
"declaration": true,
"noImplicitAny": true,
"allowUnreachableCode": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}

15
tslint.json Normal file
View File

@ -0,0 +1,15 @@
{
"rules": {
"no-string-throw": true,
"no-unused-expression": true,
"no-duplicate-variable": true,
"curly": true,
"class-name": true,
"semicolon": [
true,
"always"
],
"triple-equals": true
},
"defaultSeverity": "warning"
}