From 1608772993c5766d64cf36e94f1b3eb8d8d7208a Mon Sep 17 00:00:00 2001 From: Jorge Miguel Lobo Escalona <47326048+jloboescalona2@users.noreply.github.com> Date: Tue, 30 Nov 2021 15:55:45 +0100 Subject: [PATCH] F #5422: Add Docker tags (#1630) --- .../src/server/routes/api/market/functions.js | 151 ++++++++++++++++++ .../src/server/routes/api/market/index.js | 26 +++ .../src/server/routes/api/market/market.js | 41 +++++ .../server/routes/api/market/string-routes.js | 23 +++ .../src/server/utils/constants/defaults.js | 4 + 5 files changed, 245 insertions(+) create mode 100644 src/fireedge/src/server/routes/api/market/functions.js create mode 100644 src/fireedge/src/server/routes/api/market/index.js create mode 100644 src/fireedge/src/server/routes/api/market/market.js create mode 100644 src/fireedge/src/server/routes/api/market/string-routes.js diff --git a/src/fireedge/src/server/routes/api/market/functions.js b/src/fireedge/src/server/routes/api/market/functions.js new file mode 100644 index 0000000000..1f0820bbab --- /dev/null +++ b/src/fireedge/src/server/routes/api/market/functions.js @@ -0,0 +1,151 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed under the Apache License, Version 2.0 (the "License"); you may * + * not use this file except in compliance with the License. You may obtain * + * a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, software * + * distributed under the License is distributed on an "AS IS" BASIS, * + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and * + * limitations under the License. * + * ------------------------------------------------------------------------- */ + +const { sprintf } = require('sprintf-js') +const { request: axios } = require('axios') +const { + defaultEmptyFunction, + dockerUrl, +} = require('server/utils/constants/defaults') + +const { + Actions: ActionsMarket, +} = require('server/utils/constants/commands/market') + +const { + ok, + internalServerError, + notFound, +} = require('server/utils/constants/http-codes') +const { httpResponse } = require('server/utils/server') + +const httpNotFoundRequest = httpResponse(notFound, '', '') +const httpInternalError = httpResponse(internalServerError, '', '') + +/** + * Response http request. + * + * @param {object} res - http response + * @param {Function} next - express stepper + * @param {object} httpCode - object http code + * @param {number} httpCode.id - http code number + * @param {string} httpCode.message - http message + * @param {object} [httpCode.data] - http data + * @param {string} [httpCode.file] - file path + */ +const responseHttp = (res = {}, next = defaultEmptyFunction, httpCode) => { + if (res && res.locals && res.locals.httpCode && httpCode) { + res.locals.httpCode = httpCode + next() + } +} + +/** + * Request tags docker. + * + * @param {string} url - url docker + * @param {string[]} tags - tags + * @param {Function} error - error callback + */ +const getTagsDocker = (url = '', tags = [], error = defaultEmptyFunction) => { + axios({ + method: 'GET', + url, + headers: { + 'User-Agent': 'OpenNebula', + }, + validateStatus: (status) => status, + }) + .then(({ statusText, status, data }) => { + if (status >= 200 && status < 400 && data) { + return data + } else if (data) { + throw Error(data) + } + throw Error(statusText) + }) + .then((data) => { + const { next: dockerNext, results } = data + if (results) { + const result = Array.isArray(results) ? results : [results] + result.forEach(({ name, last_updated: lastUpdated }) => { + if (name && lastUpdated) { + tags.push({ name, last_updated: lastUpdated }) + } + }) + } + if (dockerNext) { + getTagsDocker(dockerNext, tags) + } + }) + .catch((e) => { + error(e) + }) +} + +/** + * Get Docker Hub Tags. + * + * @param {object} res - http response + * @param {Function} next - express stepper + * @param {object} params - params of http request + * @param {number} params.id - market id + * @param {object} userData - user data. + * @param {string} userData.user - ONE username + * @param {string} userData.password - ONE password + * @param {Function} oneConnection - xmlrpc function + */ +const getDockerTags = ( + res = {}, + next = defaultEmptyFunction, + params = {}, + userData = {}, + oneConnection = defaultEmptyFunction +) => { + const { id } = params + const { user, password } = userData + if (id && user && password) { + const connect = oneConnection(user, password) + connect( + ActionsMarket.MARKET_INFO, + [parseInt(id)], + (err = {}, marketAppData = {}) => { + if ( + marketAppData && + marketAppData.MARKETPLACE && + marketAppData.MARKETPLACE.NAME + ) { + const tags = [] + getTagsDocker( + sprintf(dockerUrl, marketAppData.MARKETPLACE.NAME), + tags, + () => responseHttp(res, next, httpInternalError) + ) + responseHttp(res, next, httpResponse(ok, tags)) + } else { + responseHttp(res, next, httpInternalError) + } + } + ) + } else { + responseHttp(res, next, httpNotFoundRequest) + } +} + +const functionRoutes = { + getDockerTags, +} +module.exports = functionRoutes diff --git a/src/fireedge/src/server/routes/api/market/index.js b/src/fireedge/src/server/routes/api/market/index.js new file mode 100644 index 0000000000..e526d283d2 --- /dev/null +++ b/src/fireedge/src/server/routes/api/market/index.js @@ -0,0 +1,26 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed under the Apache License, Version 2.0 (the "License"); you may * + * not use this file except in compliance with the License. You may obtain * + * a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, software * + * distributed under the License is distributed on an "AS IS" BASIS, * + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and * + * limitations under the License. * + * ------------------------------------------------------------------------- */ + +const { setApiRoutes } = require('server/utils/server') +const { routes: marketRoutes } = require('./market') +const { MARKET } = require('./string-routes') + +const functionRoutes = { + private: setApiRoutes(marketRoutes, MARKET), + public: [], +} + +module.exports = functionRoutes diff --git a/src/fireedge/src/server/routes/api/market/market.js b/src/fireedge/src/server/routes/api/market/market.js new file mode 100644 index 0000000000..99bed3b408 --- /dev/null +++ b/src/fireedge/src/server/routes/api/market/market.js @@ -0,0 +1,41 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed under the Apache License, Version 2.0 (the "License"); you may * + * not use this file except in compliance with the License. You may obtain * + * a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, software * + * distributed under the License is distributed on an "AS IS" BASIS, * + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and * + * limitations under the License. * + * ------------------------------------------------------------------------- */ + +const { + httpMethod, + from: fromData, +} = require('server/utils/constants/defaults') +const { getDockerTags } = require('./functions') +const { GET } = httpMethod + +const routes = { + [GET]: { + dockertags: { + action: getDockerTags, + params: { + id: { + from: fromData.resource, + name: 'id', + }, + }, + }, + }, +} + +const authApi = { + routes, +} +module.exports = authApi diff --git a/src/fireedge/src/server/routes/api/market/string-routes.js b/src/fireedge/src/server/routes/api/market/string-routes.js new file mode 100644 index 0000000000..aea992ccc6 --- /dev/null +++ b/src/fireedge/src/server/routes/api/market/string-routes.js @@ -0,0 +1,23 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed under the Apache License, Version 2.0 (the "License"); you may * + * not use this file except in compliance with the License. You may obtain * + * a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, software * + * distributed under the License is distributed on an "AS IS" BASIS, * + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and * + * limitations under the License. * + * ------------------------------------------------------------------------- */ + +const MARKET = 'market' + +const Actions = { + MARKET, +} + +module.exports = Actions diff --git a/src/fireedge/src/server/utils/constants/defaults.js b/src/fireedge/src/server/utils/constants/defaults.js index a546731329..7917fe0e5b 100644 --- a/src/fireedge/src/server/utils/constants/defaults.js +++ b/src/fireedge/src/server/utils/constants/defaults.js @@ -23,6 +23,8 @@ const baseUrl = `${appName ? `/${appName}/` : '/'}` const baseUrlWebsockets = 'websockets/' const severityPrepend = 'severity_' const assetsClient = '/lib/one/fireedge/dist/client' +const dockerUrl = + 'https://hub.docker.com/v2/repositories/library/%s/tags/?page_size=100' const apps = { [appNameSunstone]: { theme: appNameSunstone, @@ -38,6 +40,7 @@ const default2FAOpennebulaVar = 'TWO_FACTOR_AUTH_SECRET' const defaultIp = 'localhost' const protocol = 'http' const defaults = { + dockerUrl, defaultTypeCrypto: 'aes-256-cbc', /** * Empty function. @@ -68,6 +71,7 @@ const defaults = { '2fa', 'auth', 'files', + 'market', 'marketapp', 'oneflow', 'support',