Compare commits
1 Commits
developmen
...
user/dvasi
Author | SHA1 | Date |
---|---|---|
Dimitrios Vasilas | eb72f28599 |
|
@ -102,5 +102,5 @@ dist
|
||||||
|
|
||||||
# TernJS port file
|
# TernJS port file
|
||||||
.tern-port
|
.tern-port
|
||||||
lib/
|
lib/**
|
||||||
openapi.yaml
|
openapi.yaml
|
||||||
|
|
12
.swcrc
12
.swcrc
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "https://swc.rs/schema.json",
|
|
||||||
"jsc": {
|
|
||||||
"parser": {
|
|
||||||
"syntax": "typescript"
|
|
||||||
},
|
|
||||||
"target": "es2017"
|
|
||||||
},
|
|
||||||
"module": {
|
|
||||||
"type": "commonjs"
|
|
||||||
}
|
|
||||||
}
|
|
44
README.md
44
README.md
|
@ -1,44 +0,0 @@
|
||||||
# Scuba Client Library
|
|
||||||
|
|
||||||
This repository provides a client library for the Scuba service.
|
|
||||||
The repository also provides a CLI binary to interact with the
|
|
||||||
Scuba Service.
|
|
||||||
|
|
||||||
The supported operations are:
|
|
||||||
|
|
||||||
- Get the utilization metrics at a given time
|
|
||||||
- Get the latest utilization metrics
|
|
||||||
- Check the health of the Scuba service
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
In order to contribute, please follow the
|
|
||||||
[Contributing Guidelines](
|
|
||||||
https://github.com/scality/Guidelines/blob/master/CONTRIBUTING.md).
|
|
||||||
|
|
||||||
## Prerequisite
|
|
||||||
|
|
||||||
- Recommended Node version: >16.x.
|
|
||||||
- Yarn must be installed to build the project.
|
|
||||||
- An Open API yaml file defining the routes to use.
|
|
||||||
|
|
||||||
Node.js can be installed from [nodejs.org](https://nodejs.org/en/download/) and
|
|
||||||
Yarn can be installed from [yarnpkg.com](https://yarnpkg.com/en/docs/install).
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
To generate the client, run the following command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./bin/generate-client.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Authentication
|
|
||||||
|
|
||||||
ScubaClient supports AWS Signature Version 4 authentication. To use this
|
|
||||||
authentication method, you must have a set of credentials with permission
|
|
||||||
to perform the desired operations.
|
|
||||||
|
|
||||||
### Command-Line Interface
|
|
||||||
|
|
||||||
Command-line support is not yet available.
|
|
14
package.json
14
package.json
|
@ -10,8 +10,9 @@
|
||||||
"build": "tsc --strict",
|
"build": "tsc --strict",
|
||||||
"lint": "prettier -c $(git ls-files '*.[jt]s') && eslint $(git ls-files '*.[jt]s')",
|
"lint": "prettier -c $(git ls-files '*.[jt]s') && eslint $(git ls-files '*.[jt]s')",
|
||||||
"format": "prettier -w src && yarn lint --fix",
|
"format": "prettier -w src && yarn lint --fix",
|
||||||
"postprepare": "[ -d lib ] || swc -d lib --copy-files index.ts src",
|
"postinstall": "yarn build",
|
||||||
"prepack": "tsc --strict"
|
"prepack": "yarn build",
|
||||||
|
"prepare": "yarn build"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.20.2",
|
"@babel/core": "^7.20.2",
|
||||||
|
@ -26,22 +27,15 @@
|
||||||
"eslint": "^8.28.0",
|
"eslint": "^8.28.0",
|
||||||
"eslint-config-airbnb": "^19.0.4",
|
"eslint-config-airbnb": "^19.0.4",
|
||||||
"eslint-config-prettier": "^8.8.0",
|
"eslint-config-prettier": "^8.8.0",
|
||||||
"eslint-config-scality": "git+https://git.yourcmc.ru/vitalif/zenko-eslint-config-scality.git",
|
"eslint-config-scality": "git+https://github.com/scality/Guidelines#7.10.2",
|
||||||
"eslint-plugin-import": "^2.27.5",
|
"eslint-plugin-import": "^2.27.5",
|
||||||
"prettier": "^2.8.7",
|
"prettier": "^2.8.7",
|
||||||
"typescript": "^4.9.5"
|
"typescript": "^4.9.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-crypto/sha256-js": "^5.2.0",
|
|
||||||
"@smithy/signature-v4": "^2.1.1",
|
|
||||||
"@swc/cli": "^0.4.0",
|
|
||||||
"@swc/core": "^1.7.4",
|
|
||||||
"axios": "^1.3.4"
|
"axios": "^1.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 16"
|
"node": ">= 16"
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"typescript": "^4.9.5"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
54
src/api.ts
54
src/api.ts
|
@ -142,38 +142,6 @@ export const ScubaApiAxiosParamCreator = function (configuration?: Configuration
|
||||||
};
|
};
|
||||||
localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration);
|
localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration);
|
||||||
|
|
||||||
return {
|
|
||||||
url: toPathString(localVarUrlObj),
|
|
||||||
options: localVarRequestOptions,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {*} [options] Override http request option.
|
|
||||||
* @throws {RequiredError}
|
|
||||||
*/
|
|
||||||
healthCheck: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
|
||||||
const localVarPath = '/health/deep';
|
|
||||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
|
||||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
||||||
let baseOptions;
|
|
||||||
if (configuration) {
|
|
||||||
baseOptions = configuration.baseOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options };
|
|
||||||
const localVarHeaderParameter = {} as any;
|
|
||||||
const localVarQueryParameter = {} as any;
|
|
||||||
|
|
||||||
localVarHeaderParameter['Content-Type'] = 'application/json';
|
|
||||||
|
|
||||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
|
||||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
|
||||||
localVarRequestOptions.headers = {
|
|
||||||
...localVarHeaderParameter,
|
|
||||||
...headersFromBaseOptions,
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url: toPathString(localVarUrlObj),
|
url: toPathString(localVarUrlObj),
|
||||||
options: localVarRequestOptions,
|
options: localVarRequestOptions,
|
||||||
|
@ -236,16 +204,6 @@ export const ScubaApiFp = function (configuration?: Configuration) {
|
||||||
);
|
);
|
||||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* @param {*} [options] Override http request option.
|
|
||||||
* @throws {RequiredError}
|
|
||||||
*/
|
|
||||||
async getHealthCheck(
|
|
||||||
options?: AxiosRequestConfig,
|
|
||||||
): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
|
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.healthCheck(options);
|
|
||||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -335,16 +293,4 @@ export class ScubaApi extends BaseAPI {
|
||||||
.getMetrics(metricsClass, resourceName, metricsDate, body, options)
|
.getMetrics(metricsClass, resourceName, metricsDate, body, options)
|
||||||
.then(request => request(this.axios, this.basePath));
|
.then(request => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Health check endpoint
|
|
||||||
* @param {*} [options] Override http request option.
|
|
||||||
* @throws {RequiredError}
|
|
||||||
* @memberof ScubaApi
|
|
||||||
*/
|
|
||||||
public healthCheck(options?: AxiosRequestConfig) {
|
|
||||||
return ScubaApiFp(this.configuration)
|
|
||||||
.getHealthCheck(options)
|
|
||||||
.then(request => request(this.axios, this.basePath));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
101
src/client.ts
101
src/client.ts
|
@ -1,26 +1,12 @@
|
||||||
import * as http from 'http';
|
import * as http from 'http';
|
||||||
import * as https from 'https';
|
import * as https from 'https';
|
||||||
|
|
||||||
import { SignatureV4 } from '@smithy/signature-v4';
|
import { AxiosRequestConfig } from 'axios';
|
||||||
import globalAxios, { AxiosRequestConfig, AxiosInstance, AxiosHeaders } from 'axios';
|
|
||||||
import { Sha256 } from '@aws-crypto/sha256-js';
|
|
||||||
import { URL } from 'url';
|
|
||||||
import { parse as parseQuerystring } from 'querystring';
|
|
||||||
import { ScubaApi } from './api';
|
|
||||||
import { Configuration, ConfigurationParameters } from './configuration';
|
import { Configuration, ConfigurationParameters } from './configuration';
|
||||||
|
import { ScubaApi } from './api';
|
||||||
|
|
||||||
export type MetricsClass = 'account' | 'bucket' | 'service';
|
export type MetricsClass = 'account' | 'bucket' | 'service';
|
||||||
|
|
||||||
type WithOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
||||||
|
|
||||||
export type SignatureParameter = WithOptional<
|
|
||||||
ConstructorParameters<typeof SignatureV4>[0],
|
|
||||||
'service' | 'region' | 'sha256'
|
|
||||||
>;
|
|
||||||
export type ScubaAuth = {
|
|
||||||
awsV4?: SignatureParameter;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ScubaClientParameters = Omit<
|
export type ScubaClientParameters = Omit<
|
||||||
ConfigurationParameters,
|
ConfigurationParameters,
|
||||||
'username' | 'password' | 'accessToken' | 'formDataCtor'
|
'username' | 'password' | 'accessToken' | 'formDataCtor'
|
||||||
|
@ -32,7 +18,6 @@ export type ScubaClientParameters = Omit<
|
||||||
cert?: string;
|
cert?: string;
|
||||||
ca?: string;
|
ca?: string;
|
||||||
keepAlive?: boolean;
|
keepAlive?: boolean;
|
||||||
auth?: ScubaAuth;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ScubaMetrics = {
|
export type ScubaMetrics = {
|
||||||
|
@ -40,12 +25,6 @@ export type ScubaMetrics = {
|
||||||
bytesTotal: number;
|
bytesTotal: number;
|
||||||
metricsClass: string;
|
metricsClass: string;
|
||||||
resourceName: string;
|
resourceName: string;
|
||||||
id?: number;
|
|
||||||
date?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type HealthCheckResponse = {
|
|
||||||
date?: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function lpad(num: number, digits: number) {
|
function lpad(num: number, digits: number) {
|
||||||
|
@ -57,13 +36,8 @@ export default class ScubaClient {
|
||||||
|
|
||||||
private _defaultReqOptions: { httpAgent: http.Agent; httpsAgent: https.Agent };
|
private _defaultReqOptions: { httpAgent: http.Agent; httpsAgent: https.Agent };
|
||||||
|
|
||||||
private _axios: AxiosInstance;
|
|
||||||
|
|
||||||
/** Id of axios interceptor */
|
|
||||||
private _authInterceptor: number | null = null;
|
|
||||||
|
|
||||||
constructor(params?: ScubaClientParameters) {
|
constructor(params?: ScubaClientParameters) {
|
||||||
const { basePath, host, port, useHttps, key, cert, ca, keepAlive, auth } = params || {};
|
const { basePath, host, port, useHttps, key, cert, ca, keepAlive } = params || {};
|
||||||
const proto = useHttps ? 'https' : 'http';
|
const proto = useHttps ? 'https' : 'http';
|
||||||
const _host = host || 'localhost';
|
const _host = host || 'localhost';
|
||||||
const _port = port || 8100;
|
const _port = port || 8100;
|
||||||
|
@ -80,67 +54,16 @@ export default class ScubaClient {
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
this._axios = globalAxios.create();
|
|
||||||
|
|
||||||
// If basePath is a FQDN then it overrides the baked in config from the spec
|
// If basePath is a FQDN then it overrides the baked in config from the spec
|
||||||
this._api = new ScubaApi(new Configuration({ ...params, basePath: connectionString }), undefined, this._axios);
|
this._api = new ScubaApi(new Configuration({ ...params, basePath: connectionString }));
|
||||||
|
|
||||||
if (auth) {
|
|
||||||
this.setAuth(auth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove current auth axios interceptor and add a new one
|
|
||||||
* @param {ScubaAuth} auth Authentication method and options
|
|
||||||
* @param {Aws4InterceptorParameter} [auth.awsV4] - parameters passed to aws4-axios
|
|
||||||
* @return {undefined}
|
|
||||||
*/
|
|
||||||
setAuth(auth: ScubaAuth): void {
|
|
||||||
if (this._authInterceptor !== null && this._authInterceptor !== undefined) {
|
|
||||||
this._axios.interceptors.request.eject(this._authInterceptor);
|
|
||||||
this._authInterceptor = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auth.awsV4) {
|
|
||||||
const signer = new SignatureV4({
|
|
||||||
service: 's3',
|
|
||||||
sha256: Sha256,
|
|
||||||
region: 'us-east-1',
|
|
||||||
...auth.awsV4,
|
|
||||||
});
|
|
||||||
|
|
||||||
this._authInterceptor = this._axios.interceptors.request.use(async req => {
|
|
||||||
const { host, hostname, pathname, protocol, search } = new URL(this._axios.getUri(req));
|
|
||||||
// remove first char '?' from qs
|
|
||||||
const query = parseQuerystring(search?.substring(1)) as Record<string, string | string[]>;
|
|
||||||
|
|
||||||
const requestToSign = {
|
|
||||||
method: req.method?.toUpperCase()!,
|
|
||||||
headers: { host, ...(req.headers as Record<string, any>) },
|
|
||||||
body: req.data,
|
|
||||||
host,
|
|
||||||
hostname,
|
|
||||||
path: pathname,
|
|
||||||
protocol,
|
|
||||||
query,
|
|
||||||
};
|
|
||||||
const res = await signer.sign(requestToSign);
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
|
||||||
req.headers = new AxiosHeaders(res.headers);
|
|
||||||
return req;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getLatestMetrics(
|
async getLatestMetrics(
|
||||||
metricsClass: MetricsClass,
|
metricsClass: MetricsClass,
|
||||||
resourceName: string,
|
resourceName: string,
|
||||||
options?: AxiosRequestConfig,
|
options?: AxiosRequestConfig,
|
||||||
body?: any,
|
|
||||||
): Promise<ScubaMetrics> {
|
): Promise<ScubaMetrics> {
|
||||||
const resp = (await this._api.getLatestMetrics(metricsClass, resourceName, body, {
|
const resp = (await this._api.getLatestMetrics(metricsClass, resourceName, undefined, {
|
||||||
...this._defaultReqOptions,
|
...this._defaultReqOptions,
|
||||||
...options,
|
...options,
|
||||||
})) as any;
|
})) as any;
|
||||||
|
@ -152,21 +75,15 @@ export default class ScubaClient {
|
||||||
resourceName: string,
|
resourceName: string,
|
||||||
date: Date,
|
date: Date,
|
||||||
options?: AxiosRequestConfig,
|
options?: AxiosRequestConfig,
|
||||||
body?: any,
|
|
||||||
): Promise<ScubaMetrics> {
|
): Promise<ScubaMetrics> {
|
||||||
const year = lpad(date.getUTCFullYear(), 4);
|
const year = lpad(date.getFullYear(), 4);
|
||||||
const month = lpad(date.getUTCMonth() + 1, 2);
|
const month = lpad(date.getMonth(), 2);
|
||||||
const day = lpad(date.getUTCDate(), 2);
|
const day = lpad(date.getDate(), 2);
|
||||||
const dateString = `${year}-${month}-${day}`;
|
const dateString = `${year}-${month}-${day}`;
|
||||||
const resp = (await this._api.getMetrics(metricsClass, resourceName, dateString, body, {
|
const resp = (await this._api.getMetrics(metricsClass, resourceName, dateString, undefined, {
|
||||||
...this._defaultReqOptions,
|
...this._defaultReqOptions,
|
||||||
...options,
|
...options,
|
||||||
})) as any;
|
})) as any;
|
||||||
return resp.data;
|
return resp.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
async healthCheck(options?: AxiosRequestConfig): Promise<HealthCheckResponse> {
|
|
||||||
const resp = (await this._api.healthCheck({ ...this._defaultReqOptions, ...options })) as any;
|
|
||||||
return resp.data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue