From 8192b51ccfdb1d6beaa25ddb035ff6152c8b33bf Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 16 Jan 2019 07:35:08 -0600 Subject: [PATCH 01/21] Refactor deleteEnvironment api to trigger openshiftremove service --- node-packages/commons/src/api.js | 32 ++++----- .../src/resources/environment/resolvers.js | 71 +++++++++++++++++-- services/api/src/resources/environment/sql.js | 5 ++ services/api/src/resources/project/sql.js | 5 ++ services/api/src/typeDefs.js | 3 +- services/openshiftremove/src/index.js | 9 ++- 6 files changed, 100 insertions(+), 25 deletions(-) diff --git a/node-packages/commons/src/api.js b/node-packages/commons/src/api.js index a2ee91e67e..71cfd5dda4 100644 --- a/node-packages/commons/src/api.js +++ b/node-packages/commons/src/api.js @@ -731,24 +731,24 @@ const updateEnvironment = ( async function deleteEnvironment( name: string, project: string, + execute: boolean = true, ): Promise { - const result = await graphqlapi.query(` - { - project:projectByName(name: "${project}"){ - id - } - } - `); - - if (!result || !result.project) { - throw new ProjectNotFound(`Cannot load id for project ${project}`); + return graphqlapi.mutate( + ` + ($name: String!, $project: String!, $execute: Boolean) { + deleteEnvironment(input: { + name: $name + project: $project + execute: $execute + }) } - - return graphqlapi.query(` - mutation { - deleteEnvironment(input: {name: "${name}", project: ${result.project.id}}) - } - `); + `, + { + name, + project, + execute, + }, + ); } const getOpenShiftInfoForProject = (project: string): Promise => diff --git a/services/api/src/resources/environment/resolvers.js b/services/api/src/resources/environment/resolvers.js index c374cad45b..2542b98802 100644 --- a/services/api/src/resources/environment/resolvers.js +++ b/services/api/src/resources/environment/resolvers.js @@ -1,6 +1,8 @@ // @flow const R = require('ramda'); +const { sendToLagoonLogs } = require('@lagoon/commons/src/logs'); +const { createRemoveTask } = require('@lagoon/commons/src/tasks'); const esClient = require('../../clients/esClient'); const sqlClient = require('../../clients/sqlClient'); const { @@ -12,6 +14,8 @@ const { whereAnd, } = require('../../util/db'); const Sql = require('./sql'); +const projectSql = require('../project/sql'); +const projectHelpers = require('../project/helpers'); /* :: @@ -472,17 +476,72 @@ const addOrUpdateEnvironmentStorage = async ( const deleteEnvironment = async ( root, - { input }, - { credentials: { role } }, + { + input, + input: { + project: projectName, + name, + execute, + }, + }, + { credentials: { role, permissions: { customers, projects } } }, ) => { if (role !== 'admin') { - throw new Error('Unauthorized'); + const prep = prepare(sqlClient, 'SELECT `id` AS `pid`, `customer` AS `cid` FROM project WHERE `name` = :name'); + const rows = await query(sqlClient, prep({ name: projectName })); + + if ( + !R.contains(R.path(['0', 'pid'], rows), projects) && + !R.contains(R.path(['0', 'cid'], rows), customers) + ) { + throw new Error('Unauthorized.'); + } + } + + const projectId = await projectHelpers.getProjectIdByName(projectName); + + const projectRows = await query( + sqlClient, + projectSql.selectProject(projectId), + ); + const project = projectRows[0]; + + const environmentRows = await query( + sqlClient, + Sql.selectEnvironmentByNameAndProject(name, projectId), + ); + const environment = environmentRows[0]; + + if (!environment) { + throw new Error(`Environment "${name}" does not exist in project "${projectId}"`); } - const prep = prepare(sqlClient, 'CALL DeleteEnvironment(:name, :project)'); - await query(sqlClient, prep(input)); + if (role !== 'admin' && environment.environmentType === 'production') { + throw new Error('Unauthorized - You may not delete a production environment'); + } + + // Deleting environment in api w/o executing the openshift remove. + // This gets called by openshiftremove service after successful remove. + if (role === 'admin' && execute === false) { + const prep = prepare(sqlClient, 'CALL DeleteEnvironment(:name, :project)'); + await query(sqlClient, prep({ name, project: projectId })); + + // TODO: maybe check rows for changed result + return 'success'; + } + + const data = { + projectName: project.name, + branch: name, + type: environment.deployType, + forceDeleteProductionEnvironment: role === 'admin', + }; + + await createRemoveTask(data); + sendToLagoonLogs('info', data.projectName, '', 'api:deleteEnvironment', {}, + `*[${data.projectName}]* Deleting environment \`${data.branch}\`` + ); - // TODO: maybe check rows for changed result return 'success'; }; diff --git a/services/api/src/resources/environment/sql.js b/services/api/src/resources/environment/sql.js index b85f9d905c..1fa900db52 100644 --- a/services/api/src/resources/environment/sql.js +++ b/services/api/src/resources/environment/sql.js @@ -18,6 +18,11 @@ const Sql /* : SqlObj */ = { knex('environment') .where('id', '=', id) .toString(), + selectEnvironmentByNameAndProject: (name /* : string */, projectId /* : numbere */) => + knex('environment') + .where('name', '=', name) + .andWhere('project', '=', projectId) + .toString(), truncateEnvironment: () => knex('environment') .truncate() diff --git a/services/api/src/resources/project/sql.js b/services/api/src/resources/project/sql.js index 4f6c8c671b..a5421a5736 100644 --- a/services/api/src/resources/project/sql.js +++ b/services/api/src/resources/project/sql.js @@ -87,6 +87,11 @@ const Sql /* : SqlObj */ = { .where('project_via_user.id', projectId) .orWhere('project_via_customer.id', projectId) .toString(), + selectPermsForProject: (id /* : number */) => + knex('project') + .select({ pid: 'id', cid: 'customer' }) + .where('id', id) + .toString(), updateProject: ({ id, patch } /* : {id: number, patch: {[string]: any}} */) => knex('project') .where('id', '=', id) diff --git a/services/api/src/typeDefs.js b/services/api/src/typeDefs.js index 873b9927af..f6da54638d 100644 --- a/services/api/src/typeDefs.js +++ b/services/api/src/typeDefs.js @@ -421,7 +421,8 @@ const typeDefs = gql` input DeleteEnvironmentInput { name: String! - project: Int! + project: String! + execute: Boolean } type Query { diff --git a/services/openshiftremove/src/index.js b/services/openshiftremove/src/index.js index ef5f428b8d..b2cdb6933d 100644 --- a/services/openshiftremove/src/index.js +++ b/services/openshiftremove/src/index.js @@ -52,6 +52,11 @@ const messageConsumer = async function(msg) { environmentName = branch openshiftProject = `${safeProjectName}-${safeBranchName}` break; + + case 'promote': + environmentName = branch + openshiftProject = `${projectName}-${branch}` + break; } } catch(error) { @@ -98,7 +103,7 @@ const messageConsumer = async function(msg) { ) // Update GraphQL API that the Environment has been deleted try { - await deleteEnvironment(environmentName, projectName) + await deleteEnvironment(environmentName, projectName, false) logger.info(`${openshiftProject}: Deleted Environment '${environmentName}' in API`) } catch (err) { logger.error(err) @@ -160,7 +165,7 @@ const messageConsumer = async function(msg) { // Update GraphQL API that the Environment has been deleted try { - await deleteEnvironment(environmentName, projectName) + await deleteEnvironment(environmentName, projectName, false) logger.info(`${openshiftProject}: Deleted Environment '${environmentName}' in API`) } catch (err) { logger.error(err) From 8d47f2b32970771a07928fe320a5007ab92d9887 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 16 Jan 2019 07:35:08 -0600 Subject: [PATCH 02/21] Remove rest2tasks /remove endpoint --- services/rest2tasks/src/index.js | 72 -------------------------------- 1 file changed, 72 deletions(-) diff --git a/services/rest2tasks/src/index.js b/services/rest2tasks/src/index.js index 2df21c2ce5..f67b342e4d 100755 --- a/services/rest2tasks/src/index.js +++ b/services/rest2tasks/src/index.js @@ -377,75 +377,3 @@ app.post('/promote', async (req, res) => { } }) - - -app.post('/remove', async (req, res) => { - - req.checkBody({ - 'projectName': { - notEmpty: true, - matches: { - options: [/^[a-zA-Z0-9-_]+$/], - errorMessage: 'projectName must be defined and must only contain alphanumeric, dashes and underline' - }, - }, - 'branch': { - notEmpty: true, - matches: { - options: [/^[a-zA-Z0-9-._\/]+$/], - errorMessage: 'branch must be defined and must only contain alphanumeric, dashes, underline, dots and slashes' - }, - }, - 'forceDeleteProductionEnvironment': { - optional: {}, - isBoolean: { - errorMessage: 'should be a boolean' - } - } - }); - - const result = await req.getValidationResult() - - if (!result.isEmpty()) { - res.status(400).send('There have been validation errors: ' + util.inspect(result.mapped())); - return; - } - - const data = { - projectName: req.body.projectName, - branch: req.body.branch, - type: 'branch', - forceDeleteProductionEnvironment: req.body.forceDeleteProductionEnvironment, - } - - console.log(data) - - const meta = { - projectName: data.projectName, - branchName: data.branch - } - - try { - const taskResult = await createRemoveTask(data); - sendToLagoonLogs('info', data.projectName, '', `rest:remove:receive`, meta, - `*[${data.projectName}]* REST remove trigger \`${data.branch}\`` - ) - res.status(200).type('json').send({ "ok": "true", "message": taskResult}) - return; - } catch (error) { - switch (error.name) { - case "ProjectNotFound": - case "ActiveSystemsNotFound": - res.status(404).type('json').send({ "ok": "false", "message": error.message}) - return; - break; - - default: - logger.error(error) - res.status(500).type('json').send({ "ok": "false", "message": `Internal Error: ${error}`}) - return; - break; - } - } - -}) From 264f4d3d74910deadebd8cec3bdb9df52ef51d95 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 16 Jan 2019 07:35:08 -0600 Subject: [PATCH 03/21] Fix tests to use api for deleting environments --- tests/tasks/api/remove.yaml | 8 +++ tests/tasks/rest/remove-expect-500.yaml | 8 --- tests/tasks/rest/remove-force-production.yaml | 7 -- tests/tasks/rest/remove.yaml | 7 -- tests/tests/drupal.yaml | 5 ++ tests/tests/drupal/drupal.yaml | 4 +- tests/tests/drupal/drush.yaml | 10 +-- tests/tests/elasticsearch.yaml | 5 ++ tests/tests/elasticsearch/elasticsearch.yaml | 4 +- tests/tests/features.yaml | 8 --- .../autogenerated-routes-disabled.yaml | 6 +- tests/tests/features/cronjobs.yaml | 4 +- tests/tests/features/dot-env.yaml | 4 +- .../tests/features/environment-templates.yaml | 4 +- tests/tests/features/environment-type.yaml | 4 +- .../tests/features/lagoon-api-variables.yaml | 4 +- tests/tests/features/multiproject.yaml | 8 +-- .../production-environment-protection.yaml | 67 ------------------- tests/tests/features/promote.yaml | 10 +-- tests/tests/features/remote-shell.yaml | 6 +- tests/tests/features/route-env-variables.yaml | 4 +- tests/tests/features/subfolder.yaml | 4 +- tests/tests/nginx.yaml | 5 ++ tests/tests/nginx/nginx.yaml | 4 +- tests/tests/rest.yaml | 5 ++ tests/tests/rest/branch.yaml | 4 +- 26 files changed, 70 insertions(+), 139 deletions(-) create mode 100644 tests/tasks/api/remove.yaml delete mode 100644 tests/tasks/rest/remove-expect-500.yaml delete mode 100644 tests/tasks/rest/remove-force-production.yaml delete mode 100644 tests/tasks/rest/remove.yaml delete mode 100644 tests/tests/features/production-environment-protection.yaml diff --git a/tests/tasks/api/remove.yaml b/tests/tasks/api/remove.yaml new file mode 100644 index 0000000000..e85298121f --- /dev/null +++ b/tests/tasks/api/remove.yaml @@ -0,0 +1,8 @@ +- name: "{{ testname }} - POST api deleteEnvironment with project {{ project }} and branch {{ branch }} to {{ lookup('env','API_PROTOCOL') }}://{{ lookup('env','API_HOST') }}:{{ lookup('env','API_PORT') }}/graphql" + uri: + url: "{{ lookup('env','API_PROTOCOL') }}://{{ lookup('env','API_HOST') }}:{{ lookup('env','API_PORT') }}/graphql" + method: POST + headers: + Authorization: "Bearer {{ token.stdout }}" + body_format: json + body: '{ "query": "mutation($name: String!, $project: String!) {deleteEnvironment(input:{name:$name,project:$project})}", "variables": {"name":"{{ branch }}","project":"{{ project }}"}}' diff --git a/tests/tasks/rest/remove-expect-500.yaml b/tests/tasks/rest/remove-expect-500.yaml deleted file mode 100644 index 6cf9493645..0000000000 --- a/tests/tasks/rest/remove-expect-500.yaml +++ /dev/null @@ -1,8 +0,0 @@ -- name: "{{ testname }} - POST rest2task /remove with project {{ project }} and branch {{ branch }} to {{ lookup('env','REST2TASKS_PROTOCOL') }}://{{ lookup('env','REST2TASKS_HOST') }}:{{ lookup('env','REST2TASKS_PORT') }} expecting an 500 error" - uri: - url: "{{ lookup('env','REST2TASKS_PROTOCOL') }}://{{ lookup('env','REST2TASKS_HOST') }}:{{ lookup('env','REST2TASKS_PORT') }}/remove" - method: POST - follow_redirects: yes - status_code: 500 - body_format: json - body: '{"branch": "{{ branch }}","projectName": "{{ project }}"}' \ No newline at end of file diff --git a/tests/tasks/rest/remove-force-production.yaml b/tests/tasks/rest/remove-force-production.yaml deleted file mode 100644 index 8e0167e095..0000000000 --- a/tests/tasks/rest/remove-force-production.yaml +++ /dev/null @@ -1,7 +0,0 @@ -- name: "{{ testname }} - POST rest2task /remove with project {{ project }} and branch {{ branch }} to {{ lookup('env','REST2TASKS_PROTOCOL') }}://{{ lookup('env','REST2TASKS_HOST') }}:{{ lookup('env','REST2TASKS_PORT') }}" - uri: - url: "{{ lookup('env','REST2TASKS_PROTOCOL') }}://{{ lookup('env','REST2TASKS_HOST') }}:{{ lookup('env','REST2TASKS_PORT') }}/remove" - method: POST - follow_redirects: yes - body_format: json - body: '{"branch": "{{ branch }}","projectName": "{{ project }}", "forceDeleteProductionEnvironment": true}' \ No newline at end of file diff --git a/tests/tasks/rest/remove.yaml b/tests/tasks/rest/remove.yaml deleted file mode 100644 index 2ccd56be96..0000000000 --- a/tests/tasks/rest/remove.yaml +++ /dev/null @@ -1,7 +0,0 @@ -- name: "{{ testname }} - POST rest2task /remove with project {{ project }} and branch {{ branch }} to {{ lookup('env','REST2TASKS_PROTOCOL') }}://{{ lookup('env','REST2TASKS_HOST') }}:{{ lookup('env','REST2TASKS_PORT') }}" - uri: - url: "{{ lookup('env','REST2TASKS_PROTOCOL') }}://{{ lookup('env','REST2TASKS_HOST') }}:{{ lookup('env','REST2TASKS_PORT') }}/remove" - method: POST - follow_redirects: yes - body_format: json - body: '{"branch": "{{ branch }}","projectName": "{{ project }}"}' \ No newline at end of file diff --git a/tests/tests/drupal.yaml b/tests/tests/drupal.yaml index f841af7e58..bdb947c9aa 100644 --- a/tests/tests/drupal.yaml +++ b/tests/tests/drupal.yaml @@ -1,4 +1,9 @@ --- + +- include: features/api-token.yaml + vars: + testname: "API TOKEN" + - include: drupal/drupal.yaml vars: testname: "Drupal 8 composer PHP 7.0 - MARIADB" diff --git a/tests/tests/drupal/drupal.yaml b/tests/tests/drupal/drupal.yaml index f3525c2d4b..179f2c2dbd 100644 --- a/tests/tests/drupal/drupal.yaml +++ b/tests/tests/drupal/drupal.yaml @@ -47,14 +47,14 @@ expected_branch: "{{ branch }}" project: "{{ project }}" -- name: "{{ testname }} - rest2tasks /remove POST on {{ project }}, which should remove all resources" +- name: "{{ testname }} - api deleteEnvironment on {{ project }}, which should remove all resources" hosts: localhost serial: 1 vars: project: "{{ project }}" branch: "{{ branch }}" tasks: - - include: ../../tasks/rest/remove.yaml + - include: ../../tasks/api/remove.yaml - name: "{{ testname }} - check if site for {{ project }} does not exist anymore" hosts: localhost diff --git a/tests/tests/drupal/drush.yaml b/tests/tests/drupal/drush.yaml index ec519be790..360f37cbb3 100644 --- a/tests/tests/drupal/drush.yaml +++ b/tests/tests/drupal/drush.yaml @@ -195,23 +195,23 @@ tasks: - include: ../../checks/check-url-content.yaml -- name: "{{ testname }} - rest2tasks /remove POST on {{ project }}, which should remove all resources" +- name: "{{ testname }} - api deleteEnvironment on {{ project }}, which should remove all resources" hosts: localhost serial: 1 vars: project: "{{ project }}" branch: "drush-first" tasks: - - include: ../../tasks/rest/remove.yaml + - include: ../../tasks/api/remove.yaml -- name: "{{ testname }} - rest2tasks /remove POST on {{ project }}, which should remove all resources" +- name: "{{ testname }} - api deleteEnvironment on {{ project }}, which should remove all resources" hosts: localhost serial: 1 vars: project: "{{ project }}" branch: "drush-second" tasks: - - include: ../../tasks/rest/remove.yaml + - include: ../../tasks/api/remove.yaml - name: "{{ testname }} - check if site for {{ project }} does not exist anymore" hosts: localhost @@ -229,4 +229,4 @@ url: "http://nginx.{{ project | regex_replace('_', '-') }}.drush-second.{{ lookup('env','OPENSHIFT_ROUTE_SUFFIX') }}" expected_returncode: 503 tasks: - - include: ../../checks/check-url-returncode.yaml \ No newline at end of file + - include: ../../checks/check-url-returncode.yaml diff --git a/tests/tests/elasticsearch.yaml b/tests/tests/elasticsearch.yaml index 6214868dd0..013f128ecb 100644 --- a/tests/tests/elasticsearch.yaml +++ b/tests/tests/elasticsearch.yaml @@ -1,4 +1,9 @@ --- + +- include: features/api-token.yaml + vars: + testname: "API TOKEN" + - include: elasticsearch/elasticsearch.yaml vars: testname: "ELASTICSEARCH SINGLE NODE" diff --git a/tests/tests/elasticsearch/elasticsearch.yaml b/tests/tests/elasticsearch/elasticsearch.yaml index 3efd24e88e..404ebce82d 100644 --- a/tests/tests/elasticsearch/elasticsearch.yaml +++ b/tests/tests/elasticsearch/elasticsearch.yaml @@ -29,14 +29,14 @@ tasks: - include: ../../checks/check-json-content.yaml -- name: "{{ testname }} - rest2tasks /remove POST on {{ project }}, which should remove all resources" +- name: "{{ testname }} - api deleteEnvironment on {{ project }}, which should remove all resources" hosts: localhost serial: 1 vars: project: "{{ project }}" branch: "{{ branch }}" tasks: - - include: ../../tasks/rest/remove.yaml + - include: ../../tasks/api/remove.yaml - name: "{{ testname }} - check if site for {{ project }} does not exist anymore" hosts: localhost diff --git a/tests/tests/features.yaml b/tests/tests/features.yaml index 48834896a5..caf283dc7c 100644 --- a/tests/tests/features.yaml +++ b/tests/tests/features.yaml @@ -52,14 +52,6 @@ # not going to try hashing something in yaml. check_url: "http://node.ci-features.very-long-branch-name-what-would-otherwise-aae9.{{ lookup('env','OPENSHIFT_ROUTE_SUFFIX') }}" -- include: features/production-environment-protection.yaml - vars: - testname: "PROTECTED PRODUCTION ENVIRONMENT" - git_repo_name: features.git - project: ci-features - branch: master - check_url: "http://node.{{ project | regex_replace('_', '-') }}.{{ branch | regex_replace('/', '-') }}.{{ lookup('env','OPENSHIFT_ROUTE_SUFFIX') }}" - - include: features/environment-type.yaml vars: testname: "ENVIRONMENT TYPE DEVELOPMENT" diff --git a/tests/tests/features/autogenerated-routes-disabled.yaml b/tests/tests/features/autogenerated-routes-disabled.yaml index 6e6a87ade2..0ec5834a77 100644 --- a/tests/tests/features/autogenerated-routes-disabled.yaml +++ b/tests/tests/features/autogenerated-routes-disabled.yaml @@ -36,14 +36,14 @@ tasks: - include: ../../checks/check-url-returncode.yaml -- name: "{{ testname }} - rest2tasks /remove POST on {{ project }}, which should remove all resources" +- name: "{{ testname }} - api deleteEnvironment on {{ project }}, which should remove all resources" hosts: localhost serial: 1 vars: project: "{{ project }}" branch: "{{ branch }}" tasks: - - include: ../../tasks/rest/remove.yaml + - include: ../../tasks/api/remove.yaml - name: "{{ testname }} - check if site for {{ project }} does not exist anymore" hosts: localhost @@ -53,4 +53,4 @@ host: "customdomain.com" expected_returncode: 503 tasks: - - include: ../../checks/check-url-returncode-host.yaml \ No newline at end of file + - include: ../../checks/check-url-returncode-host.yaml diff --git a/tests/tests/features/cronjobs.yaml b/tests/tests/features/cronjobs.yaml index 3149992aa3..3cfc825b7b 100644 --- a/tests/tests/features/cronjobs.yaml +++ b/tests/tests/features/cronjobs.yaml @@ -53,14 +53,14 @@ tasks: - include: ../../checks/check-url-content.yaml -# - name: "{{ testname }} - rest2tasks /remove POST on {{ project }}, which should remove all resources" +# - name: "{{ testname }} - api deleteEnvironment on {{ project }}, which should remove all resources" # hosts: localhost # serial: 1 # vars: # project: "{{ project }}" # branch: "{{ branch }}" # tasks: -# - include: ../../tasks/rest/remove.yaml +# - include: ../../tasks/api/remove.yaml # - name: "{{ testname }} - check if site for {{ project }} does not exist anymore" # hosts: localhost diff --git a/tests/tests/features/dot-env.yaml b/tests/tests/features/dot-env.yaml index eab6e9d510..2a94539f8d 100644 --- a/tests/tests/features/dot-env.yaml +++ b/tests/tests/features/dot-env.yaml @@ -44,14 +44,14 @@ tasks: - include: ../../checks/check-url-content.yaml -- name: "{{ testname }} - rest2tasks /remove POST on {{ project }}, which should remove all resources" +- name: "{{ testname }} - api deleteEnvironment on {{ project }}, which should remove all resources" hosts: localhost serial: 1 vars: project: "{{ project }}" branch: "{{ branch }}" tasks: - - include: ../../tasks/rest/remove.yaml + - include: ../../tasks/api/remove.yaml - name: "{{ testname }} - check if site for {{ project }} does not exist anymore" hosts: localhost diff --git a/tests/tests/features/environment-templates.yaml b/tests/tests/features/environment-templates.yaml index eb54a1deb3..7e35b35c89 100644 --- a/tests/tests/features/environment-templates.yaml +++ b/tests/tests/features/environment-templates.yaml @@ -26,14 +26,14 @@ tasks: - include: ../../checks/check-url-content.yaml -- name: "{{ testname }} - rest2tasks /remove POST on {{ project }}, which should remove all resources" +- name: "{{ testname }} - api deleteEnvironment on {{ project }}, which should remove all resources" hosts: localhost serial: 1 vars: project: "{{ project }}" branch: "{{ branch }}" tasks: - - include: ../../tasks/rest/remove.yaml + - include: ../../tasks/api/remove.yaml - name: "{{ testname }} - check if site for {{ project }} does not exist anymore" hosts: localhost diff --git a/tests/tests/features/environment-type.yaml b/tests/tests/features/environment-type.yaml index 721016cc8c..2931f44d43 100644 --- a/tests/tests/features/environment-type.yaml +++ b/tests/tests/features/environment-type.yaml @@ -26,14 +26,14 @@ tasks: - include: ../../checks/check-url-content.yaml -- name: "{{ testname }} - rest2tasks /remove POST on {{ project }}, which should remove all resources" +- name: "{{ testname }} - api deleteEnvironment on {{ project }}, which should remove all resources" hosts: localhost serial: 1 vars: project: "{{ project }}" branch: "{{ branch }}" tasks: - - include: ../../tasks/rest/remove-force-production.yaml + - include: ../../tasks/api/remove.yaml - name: "{{ testname }} - check if site for {{ project }} does not exist anymore" hosts: localhost diff --git a/tests/tests/features/lagoon-api-variables.yaml b/tests/tests/features/lagoon-api-variables.yaml index 9df6321af8..f7bc158a9e 100644 --- a/tests/tests/features/lagoon-api-variables.yaml +++ b/tests/tests/features/lagoon-api-variables.yaml @@ -107,14 +107,14 @@ tasks: - include: ../../checks/check-url-content-absent.yaml -- name: "{{ testname }} - rest2tasks /remove POST on {{ project }}, which should remove all resources" +- name: "{{ testname }} - api deleteEnvironment on {{ project }}, which should remove all resources" hosts: localhost serial: 1 vars: project: "{{ project }}" branch: "{{ branch }}" tasks: - - include: ../../tasks/rest/remove-force-production.yaml + - include: ../../tasks/api/remove.yaml - name: "{{ testname }} - check if site for {{ project }} does not exist anymore" hosts: localhost diff --git a/tests/tests/features/multiproject.yaml b/tests/tests/features/multiproject.yaml index 2e88a28cad..7f83b55db3 100644 --- a/tests/tests/features/multiproject.yaml +++ b/tests/tests/features/multiproject.yaml @@ -60,23 +60,23 @@ tasks: - include: ../../checks/check-url-content-host.yaml -- name: "{{ testname }} - rest2tasks /remove POST on {{ project1 }}, which should remove all resources" +- name: "{{ testname }} - api deleteEnvironment on {{ project1 }}, which should remove all resources" hosts: localhost serial: 1 vars: project: "{{ project1 }}" branch: "{{ branch }}" tasks: - - include: ../../tasks/rest/remove.yaml + - include: ../../tasks/api/remove.yaml -- name: "{{ testname }} - rest2tasks /remove POST on {{ project2 }}, which should remove all resources" +- name: "{{ testname }} - api deleteEnvironment on {{ project2 }}, which should remove all resources" hosts: localhost serial: 1 vars: project: "{{ project2 }}" branch: "{{ branch }}" tasks: - - include: ../../tasks/rest/remove.yaml + - include: ../../tasks/api/remove.yaml - name: "{{ testname }} - check if site for {{ project1 }} does not exist anymore" hosts: localhost diff --git a/tests/tests/features/production-environment-protection.yaml b/tests/tests/features/production-environment-protection.yaml deleted file mode 100644 index 5e7ab11b64..0000000000 --- a/tests/tests/features/production-environment-protection.yaml +++ /dev/null @@ -1,67 +0,0 @@ - -- name: "{{ testname }} - init git, add files, commit, git push" - hosts: localhost - serial: 1 - vars: - git_files: "features/" - tasks: - - include: ../../tasks/git-init.yaml - - include: ../../tasks/git-add-commit-push.yaml - -- name: "{{ testname }} - rest2tasks deploy post for just git branch on {{ project }}" - hosts: localhost - serial: 1 - vars: - branch: "{{ branch }}" - project: "{{ project }}" - tasks: - - include: ../../tasks/rest/deploy-no-sha.yaml - -- include: ../../checks/check-branch-sha.yaml - vars: - expected_head: "{{ current_head }}" - expected_branch: "{{ branch }}" - project: "{{ project }}" - url: "{{ check_url }}" - -- name: "{{ testname }} - rest2tasks /remove POST on {{ project }}, expect an 500 as this branch is protected" - hosts: localhost - serial: 1 - vars: - project: "{{ project }}" - branch: "{{ branch }}" - tasks: - - include: ../../tasks/rest/remove-expect-500.yaml - -- name: "{{ testname }} - wait for 10 seconds in order to check that the production environment is still there" - hosts: localhost - serial: 1 - vars: - seconds: "10" - tasks: - - include: ../../tasks/pause.yaml - -- include: ../../checks/check-branch-sha.yaml - vars: - expected_head: "{{ current_head }}" - expected_branch: "{{ branch }}" - project: "{{ project }}" - url: "{{ check_url }}" - -- name: "{{ testname }} - rest2tasks /remove POST on {{ project }} with forceDeleteProductionEnvironment true, which should remove all resources" - hosts: localhost - serial: 1 - vars: - project: "{{ project }}" - branch: "{{ branch }}" - tasks: - - include: ../../tasks/rest/remove-force-production.yaml - -- name: "{{ testname }} - check if site for {{ project }} does not exist anymore" - hosts: localhost - serial: 1 - vars: - url: "http://{{ project | regex_replace('_', '-') }}.{{ branch | regex_replace('/', '-') }}.{{ lookup('env','OPENSHIFT_ROUTE_SUFFIX') }}" - expected_returncode: 503 - tasks: - - include: ../../checks/check-url-returncode.yaml diff --git a/tests/tests/features/promote.yaml b/tests/tests/features/promote.yaml index abd723c877..7506cd4dcc 100644 --- a/tests/tests/features/promote.yaml +++ b/tests/tests/features/promote.yaml @@ -42,23 +42,23 @@ project: "{{ project }}" url: "{{ check_url_promote }}" -- name: "{{ testname }} - rest2tasks /remove POST on {{ project }}, which should remove all resources" +- name: "{{ testname }} - api deleteEnvironment on {{ project }}, which should remove all resources" hosts: localhost serial: 1 vars: project: "{{ project }}" branch: "{{ promote_environment }}" tasks: - - include: ../../tasks/rest/remove.yaml + - include: ../../tasks/api/remove.yaml -- name: "{{ testname }} - rest2tasks /remove POST on {{ project }}, which should remove all resources" +- name: "{{ testname }} - api deleteEnvironment on {{ project }}, which should remove all resources" hosts: localhost serial: 1 vars: project: "{{ project }}" branch: "{{ source_environment }}" tasks: - - include: ../../tasks/rest/remove.yaml + - include: ../../tasks/api/remove.yaml - name: "{{ testname }} - check if site for {{ project }} does not exist anymore" hosts: localhost @@ -76,4 +76,4 @@ url: "{{ check_url_source }}" expected_returncode: 503 tasks: - - include: ../../checks/check-url-returncode.yaml \ No newline at end of file + - include: ../../checks/check-url-returncode.yaml diff --git a/tests/tests/features/remote-shell.yaml b/tests/tests/features/remote-shell.yaml index 52e5f16b14..d2d041d6fd 100644 --- a/tests/tests/features/remote-shell.yaml +++ b/tests/tests/features/remote-shell.yaml @@ -76,14 +76,14 @@ tasks: - include: ../../tasks/ssh/ssh-command.yaml -- name: "{{ testname }} - rest2tasks /remove POST on {{ project }}, which should remove all resources" +- name: "{{ testname }} - api deleteEnvironment on {{ project }}, which should remove all resources" hosts: localhost serial: 1 vars: project: "{{ project }}" branch: "{{ branch }}" tasks: - - include: ../../tasks/rest/remove.yaml + - include: ../../tasks/api/remove.yaml - name: "{{ testname }} - check if site for {{ project }} does not exist anymore" hosts: localhost @@ -92,4 +92,4 @@ url: "http://{{ project | regex_replace('_', '-') }}.{{ branch | regex_replace('/', '-') }}.{{ lookup('env','OPENSHIFT_ROUTE_SUFFIX') }}" expected_returncode: 503 tasks: - - include: ../../checks/check-url-returncode.yaml \ No newline at end of file + - include: ../../checks/check-url-returncode.yaml diff --git a/tests/tests/features/route-env-variables.yaml b/tests/tests/features/route-env-variables.yaml index 0290245559..b4495ace31 100644 --- a/tests/tests/features/route-env-variables.yaml +++ b/tests/tests/features/route-env-variables.yaml @@ -35,14 +35,14 @@ tasks: - include: ../../checks/check-url-content.yaml -- name: "{{ testname }} - rest2tasks /remove POST on {{ project }}, which should remove all resources" +- name: "{{ testname }} - api deleteEnvironment on {{ project }}, which should remove all resources" hosts: localhost serial: 1 vars: project: "{{ project }}" branch: "{{ branch }}" tasks: - - include: ../../tasks/rest/remove.yaml + - include: ../../tasks/api/remove.yaml - name: "{{ testname }} - check if site for {{ project }} does not exist anymore" hosts: localhost diff --git a/tests/tests/features/subfolder.yaml b/tests/tests/features/subfolder.yaml index 0dd18e7ae5..a4b92c0357 100644 --- a/tests/tests/features/subfolder.yaml +++ b/tests/tests/features/subfolder.yaml @@ -24,14 +24,14 @@ project: "{{ project }}" url: "{{ check_url }}" -- name: "{{ testname }} - rest2tasks /remove POST on {{ project }}, which should remove all resources" +- name: "{{ testname }} - api deleteEnvironment on {{ project }}, which should remove all resources" hosts: localhost serial: 1 vars: project: "{{ project }}" branch: "{{ branch }}" tasks: - - include: ../../tasks/rest/remove.yaml + - include: ../../tasks/api/remove.yaml - name: "{{ testname }} - check if site for {{ project }} does not exist anymore" hosts: localhost diff --git a/tests/tests/nginx.yaml b/tests/tests/nginx.yaml index 772b60c0a6..c3e529519b 100644 --- a/tests/tests/nginx.yaml +++ b/tests/tests/nginx.yaml @@ -1,4 +1,9 @@ --- + +- include: features/api-token.yaml + vars: + testname: "API TOKEN" + - include: nginx/nginx.yaml vars: testname: "NGINX" diff --git a/tests/tests/nginx/nginx.yaml b/tests/tests/nginx/nginx.yaml index 1614c4bdff..0b473082fc 100644 --- a/tests/tests/nginx/nginx.yaml +++ b/tests/tests/nginx/nginx.yaml @@ -46,14 +46,14 @@ expected_branch: "{{ branch }}" project: "{{ project }}" -- name: "{{ testname }} - rest2tasks /remove POST on {{ project }}, which should remove all resources" +- name: "{{ testname }} - api deleteEnvironment on {{ project }}, which should remove all resources" hosts: localhost serial: 1 vars: project: "{{ project }}" branch: "{{ branch }}" tasks: - - include: ../../tasks/rest/remove.yaml + - include: ../../tasks/api/remove.yaml - name: "{{ testname }} - check if site for {{ project }} does not exist anymore" hosts: localhost diff --git a/tests/tests/rest.yaml b/tests/tests/rest.yaml index 14be091d12..5131bc2a93 100644 --- a/tests/tests/rest.yaml +++ b/tests/tests/rest.yaml @@ -1,4 +1,9 @@ --- + +- include: features/api-token.yaml + vars: + testname: "API TOKEN" + - include: rest/pullrequest.yaml vars: testname: "REST - pullrequest" diff --git a/tests/tests/rest/branch.yaml b/tests/tests/rest/branch.yaml index 2770d840bb..a12a4ef531 100644 --- a/tests/tests/rest/branch.yaml +++ b/tests/tests/rest/branch.yaml @@ -89,14 +89,14 @@ project: "{{ project }}" url: "{{ check_url }}" -- name: "{{ testname }} - rest2tasks /remove POST on {{ project }}, which should remove all resources" +- name: "{{ testname }} - api deleteEnvironment on {{ project }}, which should remove all resources" hosts: localhost serial: 1 vars: project: "{{ project }}" branch: "{{ branch }}" tasks: - - include: ../../tasks/rest/remove.yaml + - include: ../../tasks/api/remove.yaml - name: "{{ testname }} - check if site for {{ project }} does not exist anymore" hosts: localhost From 86fc1238fdd0f25aefe0b232ecce7c8401d7ffca Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 16 Jan 2019 07:35:08 -0600 Subject: [PATCH 04/21] Allow deletion of environments via UI --- services/ui/package.json | 1 + .../ui/src/components/DeleteConfirm/index.js | 106 +++++++ .../ui/src/components/DeleteConfirm/logic.js | 22 ++ .../ui/src/components/Environment/index.js | 284 +++++++++++------- services/ui/src/components/Modal/index.js | 60 ++++ yarn.lock | 24 +- 6 files changed, 388 insertions(+), 109 deletions(-) create mode 100644 services/ui/src/components/DeleteConfirm/index.js create mode 100644 services/ui/src/components/DeleteConfirm/logic.js create mode 100644 services/ui/src/components/Modal/index.js diff --git a/services/ui/package.json b/services/ui/package.json index d60f4996f3..c1cd7f6551 100644 --- a/services/ui/package.json +++ b/services/ui/package.json @@ -32,6 +32,7 @@ "react-copy-to-clipboard": "^5.0.1", "react-dom": "^16.4.2", "react-highlight-words": "^0.14.0", + "react-modal": "^3.8.1", "react-select": "^2.1.1", "react-typekit": "^1.1.3", "recompose": "^0.30.0", diff --git a/services/ui/src/components/DeleteConfirm/index.js b/services/ui/src/components/DeleteConfirm/index.js new file mode 100644 index 0000000000..e650dd06bc --- /dev/null +++ b/services/ui/src/components/DeleteConfirm/index.js @@ -0,0 +1,106 @@ +import React from 'react'; +import Modal from '../Modal'; +import { color, fontSize, bp } from '../../variables'; +import withLogic from './logic'; + +const DeleteConfirm = ({ + deleteType, + deleteName, + onDelete, + inputValue, + setInputValue, + open, + openModal, + closeModal +}) => { + return ( + + + + +

+ This will delete all resources associated with the {deleteType}{' '} + {deleteName} and cannot be + undone. Make sure this is something you really want to do! +

+

Type the name of the {deleteType} to confirm.

+
+ + + cancel + + +
+
+
+ +
+ ); +}; + +export default withLogic(DeleteConfirm); diff --git a/services/ui/src/components/DeleteConfirm/logic.js b/services/ui/src/components/DeleteConfirm/logic.js new file mode 100644 index 0000000000..f3c6cab89e --- /dev/null +++ b/services/ui/src/components/DeleteConfirm/logic.js @@ -0,0 +1,22 @@ +import compose from 'recompose/compose'; +import withState from 'recompose/withState'; +import withHandlers from 'recompose/withHandlers'; + +const withInputValue = withState('inputValue', 'setInputValue', ''); +const withInputHandlers = withHandlers({ + setInputValue: ({ setInputValue }) => event => + setInputValue(event.target.value) +}); + +const withModalState = withState('open', 'setOpen', false); +const withModalHandlers = withHandlers({ + openModal: ({ setOpen }) => () => setOpen(true), + closeModal: ({ setOpen }) => () => setOpen(false) +}); + +export default compose( + withInputValue, + withInputHandlers, + withModalState, + withModalHandlers +); diff --git a/services/ui/src/components/Environment/index.js b/services/ui/src/components/Environment/index.js index 40113fedf4..ec4077515a 100644 --- a/services/ui/src/components/Environment/index.js +++ b/services/ui/src/components/Environment/index.js @@ -1,155 +1,223 @@ import React from 'react'; import Link from 'next/link'; import moment from 'moment'; +import gql from 'graphql-tag'; +import { Mutation } from 'react-apollo'; +import DeleteConfirm from '../DeleteConfirm'; import { bp, color } from '../../variables'; import giturlparse from 'git-url-parse'; +const DELETE_ENVIRONMENT_MUTATION = gql` + mutation($input: DeleteEnvironmentInput!) { + deleteEnvironment(input: $input) + } +`; + class Environment extends React.Component { constructor(props) { super(props); const gitUrlParsed = giturlparse(this.props.environment.project.gitUrl); - const gitBranchLink = `${gitUrlParsed.resource}/${gitUrlParsed.full_name}/tree/${this.props.environment.name}`; + const gitBranchLink = `${gitUrlParsed.resource}/${ + gitUrlParsed.full_name + }/tree/${this.props.environment.name}`; this.state = { gitBranchLinkWithScheme: `https://${gitBranchLink}`, - gitBranchLink: gitBranchLink, + gitBranchLink: gitBranchLink }; } render() { return ( -
-
-
-
- -
{this.props.environment.environmentType}
+
+
+
+
+ +
+ {this.props.environment.environmentType} +
+
-
-
-
- -
{this.props.environment.deployType}
+
+
+ +
{this.props.environment.deployType}
+
-
-
-
- -
{moment.utc(this.props.environment.created).local().format('DD MMM YYYY, HH:mm:ss')}
+
+
+ +
+ {moment + .utc(this.props.environment.created) + .local() + .format('DD MMM YYYY, HH:mm:ss')} +
+
-
-
-
- -
{moment.utc(this.props.environment.updated).local().format('DD MMM YYYY, HH:mm:ss')}
+
+
+ +
+ {moment + .utc(this.props.environment.updated) + .local() + .format('DD MMM YYYY, HH:mm:ss')} +
+
-
-
- -
-
- -
- {this.props.environment.routes ? this.props.environment.routes.split(',').map(route => ) : ''} +
+
+ +
+ {this.props.environment.routes + ? this.props.environment.routes.split(',').map(route => ( +
+ + {route} + +
+ )) + : ''} +
+ + {(deleteEnvironment, { loading, called, error, data }) => { + if (error) { + return
{error.message}
; + } + + if (called) { + return
Delete queued
; + } + + return ( + + deleteEnvironment({ + variables: { + input: { + name: this.props.environment.name, + project: this.props.environment.project.name + } + } + }) + } + /> + ); + }} +
-
- -
+ `} +
); } } -export default Environment; \ No newline at end of file +export default Environment; diff --git a/services/ui/src/components/Modal/index.js b/services/ui/src/components/Modal/index.js new file mode 100644 index 0000000000..9e3ca35736 --- /dev/null +++ b/services/ui/src/components/Modal/index.js @@ -0,0 +1,60 @@ +import React from 'react'; +import ReactModal from 'react-modal'; +import { color, bp } from '../../variables'; + +ReactModal.setAppElement('#__next'); + +const Modal = ({ isOpen, onRequestClose, contentLabel, children, ...rest }) => ( + + + {children} + + + +); + +export default Modal; diff --git a/yarn.lock b/yarn.lock index ce81a8dbe9..381e96b52a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4839,6 +4839,11 @@ execa@^0.7.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +exenv@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d" + integrity sha1-KueOhdmJQVhnCwPUe+wfA72Ru50= + exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -9582,11 +9587,21 @@ react-input-autosize@^2.2.1: dependencies: prop-types "^15.5.8" -react-lifecycles-compat@3.0.4, react-lifecycles-compat@^3.0.2, react-lifecycles-compat@^3.0.4: +react-lifecycles-compat@3.0.4, react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.2, react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== +react-modal@^3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.8.1.tgz#7300f94a6f92a2e17994de0be6ccb61734464c9e" + integrity sha512-aLKeZM9pgXpIKVwopRHMuvqKWiBajkqisDA8UzocdCF6S4fyKVfLWmZR5G1Q0ODBxxxxf2XIwiCP8G/11GJAuw== + dependencies: + exenv "^1.2.0" + prop-types "^15.5.10" + react-lifecycles-compat "^3.0.0" + warning "^3.0.0" + react-select@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/react-select/-/react-select-2.1.1.tgz#762d0babd8c7c46a944db51cbb72e4ee117253f9" @@ -11784,6 +11799,13 @@ walker@~1.0.5: dependencies: makeerror "1.0.x" +warning@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" + integrity sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w= + dependencies: + loose-envify "^1.0.0" + watch@~0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" From 20f8d8ff891de5c01db49ac437cd1601924c057b Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 16 Jan 2019 08:36:03 -0600 Subject: [PATCH 05/21] Fix missing api token for node tests --- tests/tests/node.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/tests/node.yaml b/tests/tests/node.yaml index ef3525e4db..fa10e95087 100644 --- a/tests/tests/node.yaml +++ b/tests/tests/node.yaml @@ -1,4 +1,9 @@ --- + +- include: features/api-token.yaml + vars: + testname: "API TOKEN" + - include: rest/branch.yaml vars: testname: "NODE 8" From 8a05f352766aaa71bf7e9856230ad1c89aa73050 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 16 Jan 2019 09:23:31 -0600 Subject: [PATCH 06/21] Fix missing api token for drupal tests --- tests/tests/drupal-galera.yaml | 5 +++++ tests/tests/drupal-postgres.yaml | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/tests/tests/drupal-galera.yaml b/tests/tests/drupal-galera.yaml index 943f2d7532..0f1b617a09 100644 --- a/tests/tests/drupal-galera.yaml +++ b/tests/tests/drupal-galera.yaml @@ -1,4 +1,9 @@ --- + +- include: features/api-token.yaml + vars: + testname: "API TOKEN" + - include: drupal/drupal.yaml vars: testname: "Drupal 8 composer PHP 7.1 - GALERA" diff --git a/tests/tests/drupal-postgres.yaml b/tests/tests/drupal-postgres.yaml index 33d5ac9437..2a5aa39c14 100644 --- a/tests/tests/drupal-postgres.yaml +++ b/tests/tests/drupal-postgres.yaml @@ -1,4 +1,9 @@ --- + +- include: features/api-token.yaml + vars: + testname: "API TOKEN" + - include: drupal/drupal.yaml vars: testname: "Drupal 8 composer PHP 7.0 - POSTGRES" From 0149b81666f1df1d29d35633d0ef0ab228e29399 Mon Sep 17 00:00:00 2001 From: Elliot Schlegelmilch Date: Thu, 17 Jan 2019 09:43:03 -0800 Subject: [PATCH 07/21] Update remote_shell.md update php connection string to reflect a useful example --- docs/using_lagoon/remote_shell.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/using_lagoon/remote_shell.md b/docs/using_lagoon/remote_shell.md index cac30f06ed..735e922322 100644 --- a/docs/using_lagoon/remote_shell.md +++ b/docs/using_lagoon/remote_shell.md @@ -47,7 +47,7 @@ ssh -p [PORT] -t [PROJECT-ENVIRONMENT-NAME]@[HOST] rsh service=[SERVICE-NAME] co As example to connect to the `php` container within the `nginx` pod: ``` -ssh -p 32222 -t drupal-example-master@ssh.lagoon.amazeeio.cloud rsh service=nginx container=pod +ssh -p 32222 -t drupal-example-master@ssh.lagoon.amazeeio.cloud rsh service=nginx container=php ``` ### Execute Commands @@ -60,4 +60,4 @@ Example: ssh -p 32222 -t drupal-example-master@ssh.lagoon.amazeeio.cloud rsh whoami ``` -Will execute `whoami` within the `cli` container. \ No newline at end of file +Will execute `whoami` within the `cli` container. From 93f4496f9c1fa13a02d9ca2a7442573c64bacfd1 Mon Sep 17 00:00:00 2001 From: Elliot Schlegelmilch Date: Fri, 18 Jan 2019 11:29:19 -0800 Subject: [PATCH 08/21] remove EOL php versions. --- docs/using_lagoon/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/using_lagoon/index.md b/docs/using_lagoon/index.md index a33c0d93da..6016436e1d 100644 --- a/docs/using_lagoon/index.md +++ b/docs/using_lagoon/index.md @@ -45,9 +45,9 @@ Some Docker Images and Containers need additional customizations from the provid | ---------------| -------------------| -------------------------------------------------------------------------------------------------------------| | nginx | 1.12 | [nginx/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/nginx/Dockerfile) | | nginx-drupal | | [nginx-drupal/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/nginx-drupal/Dockerfile) | -| [php-fpm](docker_images/php-fpm.md) | 5.6, 7.0, 7.1, 7.2 | [php/fpm/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/php/fpm/Dockerfile) | -| php-cli | 5.6, 7.0, 7.1, 7.2 | [php/cli/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/php/cli/Dockerfile) | -| php-cli-drupal | 5.6, 7.0, 7.1, 7.2 | [php/cli-drupal/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/php/cli-drupal/Dockerfile) | +| [php-fpm](docker_images/php-fpm.md) | 7.1, 7.2 | [php/fpm/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/php/fpm/Dockerfile) | +| php-cli | 7.1, 7.2 | [php/cli/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/php/cli/Dockerfile) | +| php-cli-drupal | 7.1, 7.2 | [php/cli-drupal/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/php/cli-drupal/Dockerfile) | | mariadb | 10 | [mariadb/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/mariadb/Dockerfile) | | mariadb-drupal | 10 | [mariadb-drupal/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/mariadb-drupal/Dockerfile) | | mongo | 3.6 | [mongo/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/mongo/Dockerfile) | From 64dfbdabcbfc06914460104a072642c65007a015 Mon Sep 17 00:00:00 2001 From: Elliot Schlegelmilch Date: Fri, 18 Jan 2019 11:30:08 -0800 Subject: [PATCH 09/21] my php 7.3 branch was merged. --- docs/using_lagoon/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/using_lagoon/index.md b/docs/using_lagoon/index.md index 6016436e1d..b45c32bbc4 100644 --- a/docs/using_lagoon/index.md +++ b/docs/using_lagoon/index.md @@ -45,9 +45,9 @@ Some Docker Images and Containers need additional customizations from the provid | ---------------| -------------------| -------------------------------------------------------------------------------------------------------------| | nginx | 1.12 | [nginx/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/nginx/Dockerfile) | | nginx-drupal | | [nginx-drupal/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/nginx-drupal/Dockerfile) | -| [php-fpm](docker_images/php-fpm.md) | 7.1, 7.2 | [php/fpm/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/php/fpm/Dockerfile) | -| php-cli | 7.1, 7.2 | [php/cli/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/php/cli/Dockerfile) | -| php-cli-drupal | 7.1, 7.2 | [php/cli-drupal/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/php/cli-drupal/Dockerfile) | +| [php-fpm](docker_images/php-fpm.md) | 7.1, 7.2, 7.3 | [php/fpm/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/php/fpm/Dockerfile) | +| php-cli | 7.1, 7.2, 7.3 | [php/cli/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/php/cli/Dockerfile) | +| php-cli-drupal | 7.1, 7.2, 7.3 | [php/cli-drupal/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/php/cli-drupal/Dockerfile) | | mariadb | 10 | [mariadb/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/mariadb/Dockerfile) | | mariadb-drupal | 10 | [mariadb-drupal/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/mariadb-drupal/Dockerfile) | | mongo | 3.6 | [mongo/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/mongo/Dockerfile) | From 57fc9dbaf20f4b9151ee195d3eca77c3686cc4c6 Mon Sep 17 00:00:00 2001 From: Elliot Schlegelmilch Date: Fri, 18 Jan 2019 11:31:18 -0800 Subject: [PATCH 10/21] Add solr version, add links to dockerfiles for more consistency. --- docs/using_lagoon/index.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/using_lagoon/index.md b/docs/using_lagoon/index.md index b45c32bbc4..163808435f 100644 --- a/docs/using_lagoon/index.md +++ b/docs/using_lagoon/index.md @@ -51,8 +51,9 @@ Some Docker Images and Containers need additional customizations from the provid | mariadb | 10 | [mariadb/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/mariadb/Dockerfile) | | mariadb-drupal | 10 | [mariadb-drupal/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/mariadb-drupal/Dockerfile) | | mongo | 3.6 | [mongo/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/mongo/Dockerfile) | -| solr | 5.5, 6.6 | | -| solr-drupal | 5.5, 6.6 | | -| redis | | | -| varnish | 5 | | -| varnish-drupal | 5 | | +| solr | 5.5, 6.6, 7.5 | | +| solr-drupal | 5.5, 6.6, 7.5 | | +| redis | | [redis/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/redis/Dockerfile) | +| redis-persistent | | [redis-persistent/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/redis-persistent/Dockerfile) | +| varnish | 5 | [varnish/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/varnish/Dockerfile) | +| varnish-drupal | 5 | [varnish-drupal/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/varnish-drupal/Dockerfile) | From 5ad596fb032496ccca7a75a082fcae38c0417c1f Mon Sep 17 00:00:00 2001 From: Elliot Schlegelmilch Date: Fri, 18 Jan 2019 13:27:34 -0800 Subject: [PATCH 11/21] more fill of the base images table. --- docs/using_lagoon/index.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/using_lagoon/index.md b/docs/using_lagoon/index.md index 163808435f..e5b91936fa 100644 --- a/docs/using_lagoon/index.md +++ b/docs/using_lagoon/index.md @@ -43,7 +43,7 @@ Some Docker Images and Containers need additional customizations from the provid | Type | Versions | Dockerfile | | ---------------| -------------------| -------------------------------------------------------------------------------------------------------------| -| nginx | 1.12 | [nginx/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/nginx/Dockerfile) | +| nginx | openresty/1.13.6.2 | [nginx/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/nginx/Dockerfile) | | nginx-drupal | | [nginx-drupal/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/nginx-drupal/Dockerfile) | | [php-fpm](docker_images/php-fpm.md) | 7.1, 7.2, 7.3 | [php/fpm/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/php/fpm/Dockerfile) | | php-cli | 7.1, 7.2, 7.3 | [php/cli/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/php/cli/Dockerfile) | @@ -51,9 +51,9 @@ Some Docker Images and Containers need additional customizations from the provid | mariadb | 10 | [mariadb/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/mariadb/Dockerfile) | | mariadb-drupal | 10 | [mariadb-drupal/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/mariadb-drupal/Dockerfile) | | mongo | 3.6 | [mongo/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/mongo/Dockerfile) | -| solr | 5.5, 6.6, 7.5 | | -| solr-drupal | 5.5, 6.6, 7.5 | | -| redis | | [redis/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/redis/Dockerfile) | -| redis-persistent | | [redis-persistent/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/redis-persistent/Dockerfile) | +| solr | 5.5, 6.6, 7.5 | [solr/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/solr-drupal/Dockerfile) | +| solr-drupal | 5.5, 6.6, 7.5 | [solr-drupal/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/solr-drupal/Dockerfile)| +| redis | 5.0.0 | [redis/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/redis/Dockerfile) | +| redis-persistent | 5.0.0 | [redis-persistent/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/redis-persistent/Dockerfile) | | varnish | 5 | [varnish/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/varnish/Dockerfile) | | varnish-drupal | 5 | [varnish-drupal/Dockerfile](https://github.com/amazeeio/lagoon/blob/master/images/varnish-drupal/Dockerfile) | From 88ae4b8e24cd88ac77769ba7c3c5e67ac943068b Mon Sep 17 00:00:00 2001 From: Schnitzel Date: Mon, 21 Jan 2019 09:48:25 -0600 Subject: [PATCH 12/21] addiitonal helpers and some improvements --- helpers/mariadb-galera2shared.sh | 114 ++++++++++++++++++++ helpers/mariadb-single2shared-no-nginx.sh | 106 ++++++++++++++++++ helpers/mariadb-single2shared-wordpress.sh | 120 +++++++++++++++++++++ helpers/mariadb-single2shared.sh | 2 +- 4 files changed, 341 insertions(+), 1 deletion(-) create mode 100755 helpers/mariadb-galera2shared.sh create mode 100755 helpers/mariadb-single2shared-no-nginx.sh create mode 100755 helpers/mariadb-single2shared-wordpress.sh diff --git a/helpers/mariadb-galera2shared.sh b/helpers/mariadb-galera2shared.sh new file mode 100755 index 0000000000..fffab3c708 --- /dev/null +++ b/helpers/mariadb-galera2shared.sh @@ -0,0 +1,114 @@ +#!/bin/bash + + + +if [ ! "$1" ]; then + echo "please define openshift project as first argument" + exit 1; +fi + +set -uo pipefail + +which shyaml > /dev/null +if [ $? -gt 0 ]; then + echo "please install shyaml (pip3 install shyaml)" + exit 1 +fi + +which jq > /dev/null +if [ $? -gt 0 ]; then + echo "please install jq" + exit 1 +fi + +which svcat > /dev/null +if [ $? -gt 0 ]; then + echo "please install svcat" + exit 1 +fi + +set -e + +PROJECT_NAME=$1 + +echo "*** Starting mariadb-galera --> mariadb-shared migration in ${PROJECT_NAME}" + +SERVICE_NAME=mariadb +SERVICE_NAME_UPPERCASE=$(echo $SERVICE_NAME | tr [:lower:] [:upper:]) +SERVICE_TYPE=mariadb-shared + +ENVIRONMENT_TYPE=$(oc -n $1 get configmap lagoon-env -o json | jq -r '.data.LAGOON_ENVIRONMENT_TYPE') + +OLD_POD="mariadb-galera-0" + +if [[ "$OLD_POD" ]]; then + echo "found $SERVICE_NAME pod $OLD_POD" +else + echo "no running pod found for service '${SERVICE_NAME}'', is it running?" + exit 1 +fi + +echo "*** Pausing nginx and cli" +NGINX_REPLICAS=$(oc -n $1 get dc/nginx -o json | jq -r '.spec.replicas') +CLI_REPLICAS=$(oc -n $1 get dc/cli -o json | jq -r '.spec.replicas') +oc -n $1 scale dc/nginx --replicas=0 +oc -n $1 scale dc/cli --replicas=0 + + +# create service broker +## taken from build-deploy-docker-compose.sh + +OPENSHIFT_TEMPLATE="$(git rev-parse --show-toplevel)/images/oc-build-deploy-dind/openshift-templates/${SERVICE_TYPE}/servicebroker.yml" +SERVICEBROKER_CLASS="lagoon-dbaas-mariadb-apb" +SERVICEBROKER_PLAN="${ENVIRONMENT_TYPE}" +OPENSHIFT_PROJECT=$1 +. $(git rev-parse --show-toplevel)/images/oc-build-deploy-dind/scripts/exec-openshift-create-servicebroker.sh + +# ServiceBrokers take a bit, wait until the credentials secret is available +until oc -n $1 get --insecure-skip-tls-verify secret ${SERVICE_NAME}-servicebroker-credentials +do + echo "Secret ${SERVICE_NAME}-servicebroker-credentials not available yet, waiting for 10 secs" + sleep 10 +done + +# Load credentials out of secret +SECRETS=/tmp/${PROJECT_NAME}-${OLD_POD}-migration.yaml +oc -n $1 get --insecure-skip-tls-verify secret ${SERVICE_NAME}-servicebroker-credentials -o yaml > $SECRETS + +DB_HOST=$(cat $SECRETS | shyaml get-value data.DB_HOST | base64 -D) +DB_USER=$(cat $SECRETS | shyaml get-value data.DB_USER | base64 -D) +DB_PASSWORD=$(cat $SECRETS | shyaml get-value data.DB_PASSWORD | base64 -D) +DB_NAME=$(cat $SECRETS | shyaml get-value data.DB_NAME | base64 -D) +DB_PORT=$(cat $SECRETS | shyaml get-value data.DB_PORT | base64 -D) + +echo "*** Transfering 'drupal' database from $OLD_POD to $DB_HOST" +# transfer database between from old to new +oc -n $1 exec $OLD_POD -- bash -eo pipefail -c "{ mysqldump --max-allowed-packet=500M --events --routines --quick --add-locks --no-autocommit --single-transaction --no-create-db drupal || mysqldump --max-allowed-packet=500M --events --routines --quick --add-locks --no-autocommit --single-transaction --no-create-db -S /tmp/mysql.sock -u \$MYSQL_USER -p\$MYSQL_PASSWORD \$MYSQL_DATABASE; } | sed -e 's/DEFINER[ ]*=[ ]*[^*]*\*/\*/' | mysql -h $DB_HOST -u $DB_USER -p${DB_PASSWORD} -P $DB_PORT $DB_NAME" + +CONFIG_BAK="/tmp/${PROJECT_NAME}-$(date +%F-%T)-lagoon-env.yaml" +echo "*** Backing up configmap in case we need to revert: ${CONFIG_BAK}" +oc -n $1 get configmap lagoon-env -o yaml > $CONFIG_BAK + +echo "*** updating configmap to point to ${DB_HOST}." +# Add credentials to our configmap, prefixed with the name of the servicename of this servicebroker +oc -n $1 patch --insecure-skip-tls-verify configmap lagoon-env \ + -p "{\"data\":{\"${SERVICE_NAME_UPPERCASE}_HOST\":\"${DB_HOST}\", \"${SERVICE_NAME_UPPERCASE}_USERNAME\":\"${DB_USER}\", \"${SERVICE_NAME_UPPERCASE}_PASSWORD\":\"${DB_PASSWORD}\", \"${SERVICE_NAME_UPPERCASE}_DATABASE\":\"${DB_NAME}\", \"${SERVICE_NAME_UPPERCASE}_PORT\":\"${DB_PORT}\"}}" + + +echo "*** Deleting mariadb service. Scaling old mariadb to 0; you can clean up the DC and pv later" +oc -n $1 delete service mariadb +oc -n $1 scale dc/mariadb-maxscale --replicas=0 +oc -n $1 scale statefulset/mariadb-galera --replicas=0 + + +# transfer complete, clean up +rm -f $SECRETS + +oc -n $1 scale dc/nginx --replicas=$NGINX_REPLICAS +oc -n $1 scale dc/cli --replicas=$CLI_REPLICAS + +oc -n $1 rollout latest dc/nginx +oc -n $1 rollout latest dc/cli +oc -n $1 rollout status dc/nginx +oc -n $1 rollout status dc/cli +echo "*** done." diff --git a/helpers/mariadb-single2shared-no-nginx.sh b/helpers/mariadb-single2shared-no-nginx.sh new file mode 100755 index 0000000000..8b59b98a62 --- /dev/null +++ b/helpers/mariadb-single2shared-no-nginx.sh @@ -0,0 +1,106 @@ +#!/bin/bash + + + +if [ ! "$1" ]; then + echo "please define openshift project as first argument" + exit 1; +fi + +set -uo pipefail + +which shyaml > /dev/null +if [ $? -gt 0 ]; then + echo "please install shyaml (pip3 install shyaml)" + exit 1 +fi + +which jq > /dev/null +if [ $? -gt 0 ]; then + echo "please install jq" + exit 1 +fi + +which svcat > /dev/null +if [ $? -gt 0 ]; then + echo "please install svcat" + exit 1 +fi + +set -e + +PROJECT_NAME=$1 + +echo "*** Starting mariadb-single --> mariadb-shared migration in ${PROJECT_NAME}" + +SERVICE_NAME=mariadb +SERVICE_NAME_UPPERCASE=$(echo $SERVICE_NAME | tr [:lower:] [:upper:]) +SERVICE_TYPE=mariadb-shared + +ENVIRONMENT_TYPE=$(oc -n $1 get configmap lagoon-env -o json | jq -r '.data.LAGOON_ENVIRONMENT_TYPE') + +MARIADB_REPLICAS=$(oc -n $1 get dc/mariadb -o json | jq -r '.spec.replicas') + +if [ "$MARIADB_REPLICAS" == "0" ]; then + oc -n $1 scale dc/mariadb --replicas=1 + oc -n $1 rollout status dc/mariadb +fi + +# export old mariadb pod name +OLD_POD=$(oc -n $1 get pod -o custom-columns=NAME:.metadata.name --no-headers -l service=$SERVICE_NAME) + +if [[ "$OLD_POD" ]]; then + echo "found $SERVICE_NAME pod $OLD_POD" +else + echo "no running pod found for service '${SERVICE_NAME}'', is it running?" + exit 1 +fi + +# create service broker +## taken from build-deploy-docker-compose.sh + +OPENSHIFT_TEMPLATE="$(git rev-parse --show-toplevel)/images/oc-build-deploy-dind/openshift-templates/${SERVICE_TYPE}/servicebroker.yml" +SERVICEBROKER_CLASS="lagoon-dbaas-mariadb-apb" +SERVICEBROKER_PLAN="${ENVIRONMENT_TYPE}" +OPENSHIFT_PROJECT=$1 +. $(git rev-parse --show-toplevel)/images/oc-build-deploy-dind/scripts/exec-openshift-create-servicebroker.sh + +# ServiceBrokers take a bit, wait until the credentials secret is available +until oc -n $1 get --insecure-skip-tls-verify secret ${SERVICE_NAME}-servicebroker-credentials +do + echo "Secret ${SERVICE_NAME}-servicebroker-credentials not available yet, waiting for 10 secs" + sleep 10 +done + +# Load credentials out of secret +SECRETS=/tmp/${PROJECT_NAME}-${OLD_POD}-migration.yaml +oc -n $1 get --insecure-skip-tls-verify secret ${SERVICE_NAME}-servicebroker-credentials -o yaml > $SECRETS + +DB_HOST=$(cat $SECRETS | shyaml get-value data.DB_HOST | base64 -D) +DB_USER=$(cat $SECRETS | shyaml get-value data.DB_USER | base64 -D) +DB_PASSWORD=$(cat $SECRETS | shyaml get-value data.DB_PASSWORD | base64 -D) +DB_NAME=$(cat $SECRETS | shyaml get-value data.DB_NAME | base64 -D) +DB_PORT=$(cat $SECRETS | shyaml get-value data.DB_PORT | base64 -D) + +echo "*** Transfering 'drupal' database from $OLD_POD to $DB_HOST" +# transfer database between from old to new +oc -n $1 exec $OLD_POD -- bash -eo pipefail -c "{ mysqldump --max-allowed-packet=500M --events --routines --quick --add-locks --no-autocommit --single-transaction --no-create-db \$MARIADB_DATABASE || mysqldump --max-allowed-packet=500M --events --routines --quick --add-locks --no-autocommit --single-transaction --no-create-db -S /tmp/mysql.sock -u \$MYSQL_USER -p\$MYSQL_PASSWORD \$MYSQL_DATABASE; } | mysql -h $DB_HOST -u $DB_USER -p${DB_PASSWORD} -P $DB_PORT $DB_NAME" + +CONFIG_BAK="/tmp/${PROJECT_NAME}-$(date +%F-%T)-lagoon-env.yaml" +echo "*** Backing up configmap in case we need to revert: ${CONFIG_BAK}" +oc -n $1 get configmap lagoon-env -o yaml > $CONFIG_BAK + +echo "*** updating configmap to point to ${DB_HOST}." +# Add credentials to our configmap, prefixed with the name of the servicename of this servicebroker +oc -n $1 patch --insecure-skip-tls-verify configmap lagoon-env \ + -p "{\"data\":{\"${SERVICE_NAME_UPPERCASE}_HOST\":\"${DB_HOST}\", \"${SERVICE_NAME_UPPERCASE}_USERNAME\":\"${DB_USER}\", \"${SERVICE_NAME_UPPERCASE}_PASSWORD\":\"${DB_PASSWORD}\", \"${SERVICE_NAME_UPPERCASE}_DATABASE\":\"${DB_NAME}\", \"${SERVICE_NAME_UPPERCASE}_PORT\":\"${DB_PORT}\"}}" + + +echo "*** Deleting mariadb service. Scaling old mariadb to 0; you can clean up the DC and pv later" +oc -n $1 delete service mariadb +oc -n $1 scale dc/mariadb --replicas=0 + +# transfer complete, clean up +rm -f $SECRETS + +echo "*** done." diff --git a/helpers/mariadb-single2shared-wordpress.sh b/helpers/mariadb-single2shared-wordpress.sh new file mode 100755 index 0000000000..13461cfbf5 --- /dev/null +++ b/helpers/mariadb-single2shared-wordpress.sh @@ -0,0 +1,120 @@ +#!/bin/bash + + + +if [ ! "$1" ]; then + echo "please define openshift project as first argument" + exit 1; +fi + +set -uo pipefail + +which shyaml > /dev/null +if [ $? -gt 0 ]; then + echo "please install shyaml (pip3 install shyaml)" + exit 1 +fi + +which jq > /dev/null +if [ $? -gt 0 ]; then + echo "please install jq" + exit 1 +fi + +which svcat > /dev/null +if [ $? -gt 0 ]; then + echo "please install svcat" + exit 1 +fi + +set -e + +PROJECT_NAME=$1 + +echo "*** Starting mariadb-single --> mariadb-shared migration in ${PROJECT_NAME}" + +SERVICE_NAME=mariadb +SERVICE_NAME_UPPERCASE=$(echo $SERVICE_NAME | tr [:lower:] [:upper:]) +SERVICE_TYPE=mariadb-shared + +ENVIRONMENT_TYPE=$(oc -n $1 get configmap lagoon-env -o json | jq -r '.data.LAGOON_ENVIRONMENT_TYPE') + +MARIADB_REPLICAS=$(oc -n $1 get dc/mariadb -o json | jq -r '.spec.replicas') + +if [ "$MARIADB_REPLICAS" == "0" ]; then + oc -n $1 scale dc/mariadb --replicas=1 + oc -n $1 rollout status dc/mariadb +fi + +# export old mariadb pod name +OLD_POD=$(oc -n $1 get pod -o custom-columns=NAME:.metadata.name --no-headers -l service=$SERVICE_NAME) + +if [[ "$OLD_POD" ]]; then + echo "found $SERVICE_NAME pod $OLD_POD" +else + echo "no running pod found for service '${SERVICE_NAME}'', is it running?" + exit 1 +fi + +echo "*** Pausing nginx and cli" +NGINX_REPLICAS=$(oc -n $1 get dc/nginx -o json | jq -r '.spec.replicas') +CLI_REPLICAS=$(oc -n $1 get dc/cli -o json | jq -r '.spec.replicas') +oc -n $1 scale dc/nginx --replicas=0 +oc -n $1 scale dc/cli --replicas=0 + + +# create service broker +## taken from build-deploy-docker-compose.sh + +OPENSHIFT_TEMPLATE="$(git rev-parse --show-toplevel)/images/oc-build-deploy-dind/openshift-templates/${SERVICE_TYPE}/servicebroker.yml" +SERVICEBROKER_CLASS="lagoon-dbaas-mariadb-apb" +SERVICEBROKER_PLAN="${ENVIRONMENT_TYPE}" +OPENSHIFT_PROJECT=$1 +. $(git rev-parse --show-toplevel)/images/oc-build-deploy-dind/scripts/exec-openshift-create-servicebroker.sh + +# ServiceBrokers take a bit, wait until the credentials secret is available +until oc -n $1 get --insecure-skip-tls-verify secret ${SERVICE_NAME}-servicebroker-credentials +do + echo "Secret ${SERVICE_NAME}-servicebroker-credentials not available yet, waiting for 10 secs" + sleep 10 +done + +# Load credentials out of secret +SECRETS=/tmp/${PROJECT_NAME}-${OLD_POD}-migration.yaml +oc -n $1 get --insecure-skip-tls-verify secret ${SERVICE_NAME}-servicebroker-credentials -o yaml > $SECRETS + +DB_HOST=$(cat $SECRETS | shyaml get-value data.DB_HOST | base64 -D) +DB_USER=$(cat $SECRETS | shyaml get-value data.DB_USER | base64 -D) +DB_PASSWORD=$(cat $SECRETS | shyaml get-value data.DB_PASSWORD | base64 -D) +DB_NAME=$(cat $SECRETS | shyaml get-value data.DB_NAME | base64 -D) +DB_PORT=$(cat $SECRETS | shyaml get-value data.DB_PORT | base64 -D) + +echo "*** Transfering 'drupal' database from $OLD_POD to $DB_HOST" +# transfer database between from old to new +oc -n $1 exec $OLD_POD -- bash -eo pipefail -c "{ mysqldump --max-allowed-packet=500M --events --routines --quick --add-locks --no-autocommit --single-transaction --no-create-db lagoon || mysqldump --max-allowed-packet=500M --events --routines --quick --add-locks --no-autocommit --single-transaction --no-create-db -S /tmp/mysql.sock -u \$MYSQL_USER -p\$MYSQL_PASSWORD \$MYSQL_DATABASE; } | sed -e 's/DEFINER[ ]*=[ ]*[^*]*\*/\*/' | mysql -h $DB_HOST -u $DB_USER -p${DB_PASSWORD} -P $DB_PORT $DB_NAME" + +CONFIG_BAK="/tmp/${PROJECT_NAME}-$(date +%F-%T)-lagoon-env.yaml" +echo "*** Backing up configmap in case we need to revert: ${CONFIG_BAK}" +oc -n $1 get configmap lagoon-env -o yaml > $CONFIG_BAK + +echo "*** updating configmap to point to ${DB_HOST}." +# Add credentials to our configmap, prefixed with the name of the servicename of this servicebroker +oc -n $1 patch --insecure-skip-tls-verify configmap lagoon-env \ + -p "{\"data\":{\"${SERVICE_NAME_UPPERCASE}_HOST\":\"${DB_HOST}\", \"${SERVICE_NAME_UPPERCASE}_USERNAME\":\"${DB_USER}\", \"${SERVICE_NAME_UPPERCASE}_PASSWORD\":\"${DB_PASSWORD}\", \"${SERVICE_NAME_UPPERCASE}_DATABASE\":\"${DB_NAME}\", \"${SERVICE_NAME_UPPERCASE}_PORT\":\"${DB_PORT}\"}}" + + +echo "*** Deleting mariadb service. Scaling old mariadb to 0; you can clean up the DC and pv later" +oc -n $1 delete service mariadb +oc -n $1 scale dc/mariadb --replicas=0 + +# transfer complete, clean up +rm -f $SECRETS + +oc -n $1 scale dc/nginx --replicas=$NGINX_REPLICAS +oc -n $1 scale dc/cli --replicas=$CLI_REPLICAS + +oc -n $1 rollout latest dc/nginx +oc -n $1 rollout latest dc/cli +oc -n $1 rollout status dc/nginx +oc -n $1 rollout status dc/cli +echo "*** done." diff --git a/helpers/mariadb-single2shared.sh b/helpers/mariadb-single2shared.sh index 09709f02fa..9a281271bd 100755 --- a/helpers/mariadb-single2shared.sh +++ b/helpers/mariadb-single2shared.sh @@ -91,7 +91,7 @@ DB_PORT=$(cat $SECRETS | shyaml get-value data.DB_PORT | base64 -D) echo "*** Transfering 'drupal' database from $OLD_POD to $DB_HOST" # transfer database between from old to new -oc -n $1 exec $OLD_POD -- bash -eo pipefail -c "{ mysqldump --max-allowed-packet=500M --events --routines --quick --add-locks --no-autocommit --single-transaction --no-create-db drupal || mysqldump --max-allowed-packet=500M --events --routines --quick --add-locks --no-autocommit --single-transaction --no-create-db -S /tmp/mysql.sock -u \$MYSQL_USER -p\$MYSQL_PASSWORD \$MYSQL_DATABASE; } | mysql -h $DB_HOST -u $DB_USER -p${DB_PASSWORD} -P $DB_PORT $DB_NAME" +oc -n $1 exec $OLD_POD -- bash -eo pipefail -c "{ mysqldump --max-allowed-packet=500M --events --routines --quick --add-locks --no-autocommit --single-transaction --no-create-db drupal || mysqldump --max-allowed-packet=500M --events --routines --quick --add-locks --no-autocommit --single-transaction --no-create-db -S /tmp/mysql.sock -u \$MYSQL_USER -p\$MYSQL_PASSWORD \$MYSQL_DATABASE; } | sed -e 's/DEFINER[ ]*=[ ]*[^*]*\*/\*/' | mysql -h $DB_HOST -u $DB_USER -p${DB_PASSWORD} -P $DB_PORT $DB_NAME" CONFIG_BAK="/tmp/${PROJECT_NAME}-$(date +%F-%T)-lagoon-env.yaml" echo "*** Backing up configmap in case we need to revert: ${CONFIG_BAK}" From 5706cfaa5ff2a1a37ccde5d029beceb5b06213da Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Mon, 21 Jan 2019 10:32:41 -0600 Subject: [PATCH 13/21] Fix pullrequest environment deletes in api --- .../src/resources/environment/resolvers.js | 34 ++++++++-- services/rest2tasks/src/index.js | 66 ------------------- tests/tasks/rest/pullrequest-remove.yaml | 8 --- tests/tests/rest/pullrequest.yaml | 7 +- 4 files changed, 34 insertions(+), 81 deletions(-) delete mode 100644 tests/tasks/rest/pullrequest-remove.yaml diff --git a/services/api/src/resources/environment/resolvers.js b/services/api/src/resources/environment/resolvers.js index 2542b98802..5f33d59cf6 100644 --- a/services/api/src/resources/environment/resolvers.js +++ b/services/api/src/resources/environment/resolvers.js @@ -530,16 +530,42 @@ const deleteEnvironment = async ( return 'success'; } - const data = { + let data = { projectName: project.name, - branch: name, type: environment.deployType, forceDeleteProductionEnvironment: role === 'admin', }; + const meta = { + projectName: data.projectName, + environmentName: environment.name, + }; + + switch (environment.deployType) { + case 'branch': + data = { + ...data, + branch: name, + }; + break; + + case 'pullrequest': + data = { + ...data, + pullrequestNumber: environment.name.replace('pr-', ''), + }; + break; + + default: + sendToLagoonLogs('error', data.projectName, '', 'api:deleteEnvironment:error', meta, + `*[${data.projectName}]* Unknown deploy type ${environment.deployType} \`${environment.name}\`` + ); + return `Error: unknown deploy type ${environment.deployType}`; + } + await createRemoveTask(data); - sendToLagoonLogs('info', data.projectName, '', 'api:deleteEnvironment', {}, - `*[${data.projectName}]* Deleting environment \`${data.branch}\`` + sendToLagoonLogs('info', data.projectName, '', 'api:deleteEnvironment', meta, + `*[${data.projectName}]* Deleting environment \`${environment.name}\`` ); return 'success'; diff --git a/services/rest2tasks/src/index.js b/services/rest2tasks/src/index.js index f67b342e4d..081779f997 100755 --- a/services/rest2tasks/src/index.js +++ b/services/rest2tasks/src/index.js @@ -143,72 +143,6 @@ app.post('/pullrequest/deploy', async (req, res) => { }) - -app.post('/pullrequest/remove', async (req, res) => { - - req.checkBody({ - 'projectName': { - notEmpty: true, - matches: { - options: [/^[a-zA-Z0-9-_]+$/], - errorMessage: 'projectName must be defined and must only contain alphanumeric, dashes and underline' - }, - }, - 'pullrequestNumber': { - notEmpty: true, - isInt: {}, - matches: { - errorMessage: 'pullrequestNumber must be defined and a number' - }, - } - }); - - const result = await req.getValidationResult() - - if (!result.isEmpty()) { - res.status(400).send('There have been validation errors: ' + util.inspect(result.mapped())); - return; - } - - const data = { - projectName: req.body.projectName, - pullrequestNumber: req.body.pullrequestNumber, - type: 'pullrequest' - } - - const meta = { - projectName: data.projectName, - pullrequestNumber: data.pullrequestNumber - } - - try { - const taskResult = await createRemoveTask(data); - - sendToLagoonLogs('info', data.projectName, '', `rest:pullrequest:remove`, meta, - `*[${data.projectName}]* REST remove trigger \`${data.pullrequestNumber}\`` - ) - - res.status(200).type('json').send({ "ok": "true", "message": taskResult}) - return; - } catch (error) { - switch (error.name) { - case "ProjectNotFound": - case "ActiveSystemsNotFound": - case "UnknownActiveSystem": - res.status(404).type('json').send({ "ok": "false", "message": error.message}) - return; - break; - - default: - logger.error(error) - res.status(500).type('json').send({ "ok": "false", "message": `Internal Error: ${error}`}) - return; - break; - } - } - -}) - app.post('/deploy', async (req, res) => { req.checkBody({ diff --git a/tests/tasks/rest/pullrequest-remove.yaml b/tests/tasks/rest/pullrequest-remove.yaml deleted file mode 100644 index 2761869f9c..0000000000 --- a/tests/tasks/rest/pullrequest-remove.yaml +++ /dev/null @@ -1,8 +0,0 @@ -- name: "{{ testname }} - POST rest2task /pullrequest/remove with with pr number {{ git_pr_number }} to {{ lookup('env','REST2TASKS_PROTOCOL') }}://{{ lookup('env','REST2TASKS_HOST') }}:{{ lookup('env','REST2TASKS_PORT') }}" - uri: - url: "{{ lookup('env','REST2TASKS_PROTOCOL') }}://{{ lookup('env','REST2TASKS_HOST') }}:{{ lookup('env','REST2TASKS_PORT') }}/pullrequest/remove" - method: POST - follow_redirects: yes - body_format: json - body: '{"projectName": "{{ project }}", "pullrequestNumber": "{{ git_pr_number }}" }' - diff --git a/tests/tests/rest/pullrequest.yaml b/tests/tests/rest/pullrequest.yaml index 1ea0cd0f0c..db4522514a 100644 --- a/tests/tests/rest/pullrequest.yaml +++ b/tests/tests/rest/pullrequest.yaml @@ -107,13 +107,14 @@ expected_pr_head_sha: "{{ pr_2nd_commit_hash }}" expected_pr_title: "PR Title - UPDATE" -- name: "{{ testname }} - rest pull request delete" +- name: "{{ testname }} - api deleteEnvironment on {{ project }}, which should remove all resources" hosts: localhost serial: 1 vars: - git_pr_number: "1" + project: "{{ project }}" + branch: "pr-1" tasks: - - include: ../../tasks/rest/pullrequest-remove.yaml + - include: ../../tasks/api/remove.yaml - name: "{{ testname }} - check if site for project does not exist anymore" hosts: localhost From ccf581a8878559f0f2716a8c84492b64b8853f9f Mon Sep 17 00:00:00 2001 From: Elliot Schlegelmilch Date: Mon, 21 Jan 2019 11:10:58 -0800 Subject: [PATCH 14/21] warn on stderr about old php versions. --- images/php/fpm/Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/images/php/fpm/Dockerfile b/images/php/fpm/Dockerfile index 916a1227e1..0a2f3ee797 100644 --- a/images/php/fpm/Dockerfile +++ b/images/php/fpm/Dockerfile @@ -93,6 +93,9 @@ RUN apk update \ && fix-permissions /app \ && fix-permissions /etc/ssmtp/ssmtp.conf +RUN if [ ${PHP_VERSION%.*} == "5.6" ] || [ ${PHP_VERSION%.*} == "7.0" ] ; then \ + echo echo \"PHP ${PHP_VERSION} is end of life and should no longer be used. For more information, visit https://secure.php.net/eol.php\" \> /dev/stderr > /home/.bashrc ; fi + EXPOSE 9000 ENV AMAZEEIO_DB_HOST=mariadb \ From 58aef86f494d0e36fa9d5638212c10364e2d5c91 Mon Sep 17 00:00:00 2001 From: Elliot Schlegelmilch Date: Mon, 21 Jan 2019 14:11:50 -0800 Subject: [PATCH 15/21] move version check to cli image. --- images/php/cli/Dockerfile | 3 +++ images/php/fpm/Dockerfile | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/images/php/cli/Dockerfile b/images/php/cli/Dockerfile index 47c2f71cbf..fa48217b8d 100644 --- a/images/php/cli/Dockerfile +++ b/images/php/cli/Dockerfile @@ -54,6 +54,9 @@ RUN echo "source /lagoon/entrypoints/61-php-xdebug-cli-env.sh" >> /home/.bashrc COPY 55-cli-helpers.sh /lagoon/entrypoints/ RUN echo "source /lagoon/entrypoints/55-cli-helpers.sh" >> /home/.bashrc +RUN if [ ${PHP_VERSION%.*} == "5.6" ] || [ ${PHP_VERSION%.*} == "7.0" ] ; then \ + echo echo \"PHP ${PHP_VERSION} is end of life and should no longer be used. For more information, visit https://secure.php.net/eol.php\" \> /dev/stderr > /home/.bashrc ; fi + # SSH Key and Agent Setup COPY 05-ssh-key.sh /lagoon/entrypoints/ COPY 10-ssh-agent.sh /lagoon/entrypoints/ diff --git a/images/php/fpm/Dockerfile b/images/php/fpm/Dockerfile index 0a2f3ee797..916a1227e1 100644 --- a/images/php/fpm/Dockerfile +++ b/images/php/fpm/Dockerfile @@ -93,9 +93,6 @@ RUN apk update \ && fix-permissions /app \ && fix-permissions /etc/ssmtp/ssmtp.conf -RUN if [ ${PHP_VERSION%.*} == "5.6" ] || [ ${PHP_VERSION%.*} == "7.0" ] ; then \ - echo echo \"PHP ${PHP_VERSION} is end of life and should no longer be used. For more information, visit https://secure.php.net/eol.php\" \> /dev/stderr > /home/.bashrc ; fi - EXPOSE 9000 ENV AMAZEEIO_DB_HOST=mariadb \ From cdd19eb9efb52652f1e702f70dd7360835dbf4cc Mon Sep 17 00:00:00 2001 From: Elliot Schlegelmilch Date: Mon, 21 Jan 2019 14:26:07 -0800 Subject: [PATCH 16/21] append to bashrc. --- images/php/cli/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/php/cli/Dockerfile b/images/php/cli/Dockerfile index fa48217b8d..a7a29bec6e 100644 --- a/images/php/cli/Dockerfile +++ b/images/php/cli/Dockerfile @@ -55,7 +55,7 @@ COPY 55-cli-helpers.sh /lagoon/entrypoints/ RUN echo "source /lagoon/entrypoints/55-cli-helpers.sh" >> /home/.bashrc RUN if [ ${PHP_VERSION%.*} == "5.6" ] || [ ${PHP_VERSION%.*} == "7.0" ] ; then \ - echo echo \"PHP ${PHP_VERSION} is end of life and should no longer be used. For more information, visit https://secure.php.net/eol.php\" \> /dev/stderr > /home/.bashrc ; fi + echo echo \"PHP ${PHP_VERSION} is end of life and should no longer be used. For more information, visit https://secure.php.net/eol.php\" \> /dev/stderr >> /home/.bashrc ; fi # SSH Key and Agent Setup COPY 05-ssh-key.sh /lagoon/entrypoints/ From 9eb1bf8f53dfd19f71c059ad9c5aaf4dffd693d6 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Tue, 22 Jan 2019 14:43:28 -0600 Subject: [PATCH 17/21] Select environmment via name AND project --- services/api-db/docker-entrypoint-initdb.d/03-procedures.sql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/api-db/docker-entrypoint-initdb.d/03-procedures.sql b/services/api-db/docker-entrypoint-initdb.d/03-procedures.sql index 89398fd2a6..a53e1bf73f 100644 --- a/services/api-db/docker-entrypoint-initdb.d/03-procedures.sql +++ b/services/api-db/docker-entrypoint-initdb.d/03-procedures.sql @@ -164,7 +164,8 @@ CREATE OR REPLACE PROCEDURE e.* FROM environment e WHERE e.name = name AND - deleted = '0000-00-00 00:00:00'; + e.project = pid AND + e.deleted = '0000-00-00 00:00:00'; END; $$ From b6de96afff0c1df0223a6a4cae9d8a6606ca1c41 Mon Sep 17 00:00:00 2001 From: Schnitzel Date: Tue, 22 Jan 2019 14:44:59 -0600 Subject: [PATCH 18/21] add local-minio for testing S3 Storage of Files --- docker-compose.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docker-compose.yaml b/docker-compose.yaml index 8818918660..319188f606 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -290,6 +290,17 @@ services: - ./local-dev/api-data-watcher-pusher:/home labels: lagoon.type: none + local-minio: + image: minio/minio + entrypoint: sh + command: -c 'mkdir -p /export/lagoon-files && /usr/bin/minio server /export' + ports: + - '9000:9000' + environment: + - MINIO_ACCESS_KEY=minio + - MINIO_SECRET_KEY=minio123 + labels: + lagoon.type: none drush-alias: image: ${IMAGE_REPO:-lagoon}/drush-alias volumes: From 356d452a1a91435ee0a2141413ec71d7158c5ff0 Mon Sep 17 00:00:00 2001 From: Schnitzel Date: Tue, 22 Jan 2019 14:45:55 -0600 Subject: [PATCH 19/21] Add DrushSqlDump and DrushCacheClear Tasks --- services/api/src/clients/aws.js | 6 +- services/api/src/resolvers.js | 4 + services/api/src/resources/task/resolvers.js | 78 ++++++++++++++- services/api/src/typeDefs.js | 2 + .../AddTask/components/DrushCacheClear.js | 96 +++++++++++++++++++ .../AddTask/components/DrushSqlDump.js | 96 +++++++++++++++++++ services/ui/src/components/AddTask/index.js | 4 + services/ui/src/components/AddTask/logic.js | 17 +++- services/ui/src/components/NavTabs/index.js | 4 +- services/ui/src/components/Task/index.js | 8 -- 10 files changed, 294 insertions(+), 21 deletions(-) create mode 100644 services/ui/src/components/AddTask/components/DrushCacheClear.js create mode 100644 services/ui/src/components/AddTask/components/DrushSqlDump.js diff --git a/services/api/src/clients/aws.js b/services/api/src/clients/aws.js index 5d42302ae5..45f599dbd8 100644 --- a/services/api/src/clients/aws.js +++ b/services/api/src/clients/aws.js @@ -4,9 +4,9 @@ const R = require('ramda'); const AWS = require('aws-sdk'); const s3Host = R.propOr('http://docker.for.mac.localhost:9000', 'S3_HOST', process.env); -const accessKeyId = R.propOr('minio', 'S3_ACCESS_KEY_ID', process.env); -const secretAccessKey = R.propOr('minio123', 'S3_SECRET_ACCESS_KEY', process.env); -const bucket = R.propOr('api-files', 'S3_BUCKET', process.env); +const accessKeyId = R.propOr('minio', 'S3_ACCESS_KEY_ID', process.env); +const secretAccessKey = R.propOr('minio123', 'S3_SECRET_ACCESS_KEY', process.env); +const bucket = R.propOr('lagoon-files', 'S3_BUCKET', process.env); const s3 = new AWS.S3({ endpoint: s3Host, diff --git a/services/api/src/resolvers.js b/services/api/src/resolvers.js index 25759e9887..8158926c16 100644 --- a/services/api/src/resolvers.js +++ b/services/api/src/resolvers.js @@ -29,6 +29,8 @@ const { deleteTask, updateTask, taskDrushArchiveDump, + taskDrushSqlDump, + taskDrushCacheClear, taskDrushSqlSync, taskDrushRsyncFiles, taskSubscriber, @@ -273,6 +275,8 @@ const resolvers /* : { [string]: ResolversObj | typeof GraphQLDate } */ = { deleteEnvVariable, addTask, taskDrushArchiveDump, + taskDrushSqlDump, + taskDrushCacheClear, taskDrushSqlSync, taskDrushRsyncFiles, deleteTask, diff --git a/services/api/src/resources/task/resolvers.js b/services/api/src/resources/task/resolvers.js index aea05fc91c..fcb66bac9d 100644 --- a/services/api/src/resources/task/resolvers.js +++ b/services/api/src/resources/task/resolvers.js @@ -262,12 +262,12 @@ const taskDrushArchiveDump = async ( await envValidators.userAccessEnvironment(credentials, environmentId); await envValidators.environmentHasService(environmentId, 'cli'); - const command = String.raw`drush ard --pipe | \ -xargs -I_file curl -sS "$TASK_API_HOST"/graphql \ + const command = String.raw`file="/tmp/$LAGOON_SAFE_PROJECT-$LAGOON_GIT_SAFE_BRANCH-$(date --iso-8601=seconds).tar" && drush ard --destination=$file && \ +curl -sS "$TASK_API_HOST"/graphql \ -H "Authorization: Bearer $TASK_API_AUTH" \ -F operations='{ "query": "mutation ($task: Int!, $files: [Upload!]!) { uploadFilesForTask(input:{task:$task, files:$files}) { id files { filename } } }", "variables": { "task": '"$TASK_DATA_ID"', "files": [null] } }' \ -F map='{ "0": ["variables.files.0"] }' \ --F 0=@_file +-F 0=@$file; rm -rf $file; `; const taskData = await Helpers.addTask({ @@ -281,6 +281,73 @@ xargs -I_file curl -sS "$TASK_API_HOST"/graphql \ return taskData; }; +const taskDrushSqlDump = async ( + root, + { + environment: environmentId, + }, + { + credentials, + }, +) => { + await envValidators.environmentExists(environmentId); + await envValidators.userAccessEnvironment(credentials, environmentId); + await envValidators.environmentHasService(environmentId, 'cli'); + + const command = String.raw`file="/tmp/$LAGOON_SAFE_PROJECT-$LAGOON_GIT_SAFE_BRANCH-$(date --iso-8601=seconds).sql" && drush sql-dump --result-file=$file --gzip && \ +curl -sS "$TASK_API_HOST"/graphql \ +-H "Authorization: Bearer $TASK_API_AUTH" \ +-F operations='{ "query": "mutation ($task: Int!, $files: [Upload!]!) { uploadFilesForTask(input:{task:$task, files:$files}) { id files { filename } } }", "variables": { "task": '"$TASK_DATA_ID"', "files": [null] } }' \ +-F map='{ "0": ["variables.files.0"] }' \ +-F 0=@$file.gz; rm -rf $file.gz +`; + + const taskData = await Helpers.addTask({ + name: 'Drush sql-dump', + environment: environmentId, + service: 'cli', + command, + execute: true, + }); + + return taskData; +}; + +const taskDrushCacheClear = async ( + root, + { + environment: environmentId, + }, + { + credentials, + }, +) => { + await envValidators.environmentExists(environmentId); + await envValidators.userAccessEnvironment(credentials, environmentId); + await envValidators.environmentHasService(environmentId, 'cli'); + + const command = 'drupal_version=$(drush status drupal-version --format=list) && \ + if [ ${drupal_version%.*.*} == "8" ]; then \ + drush cr; \ + elif [ ${drupal_version%.*} == "7" ]; then \ + drush cc all; \ + else \ + echo \"could not clear cache for found Drupal Version ${drupal_version}\"; \ + exit 1; \ + fi'; + + + const taskData = await Helpers.addTask({ + name: 'Drush cache-clear', + environment: environmentId, + service: 'cli', + command, + execute: true, + }); + + return taskData; +}; + const taskDrushSqlSync = async ( root, { @@ -347,7 +414,7 @@ const taskSubscriber = createEnvironmentFilteredSubscriber( [ EVENTS.TASK.ADDED, EVENTS.TASK.UPDATED, - ] + ], ); const Resolvers /* : ResolversObj */ = { @@ -357,9 +424,12 @@ const Resolvers /* : ResolversObj */ = { deleteTask, updateTask, taskDrushArchiveDump, + taskDrushSqlDump, + taskDrushCacheClear, taskDrushSqlSync, taskDrushRsyncFiles, taskSubscriber, }; + module.exports = Resolvers; diff --git a/services/api/src/typeDefs.js b/services/api/src/typeDefs.js index 873b9927af..c4e028bb8d 100644 --- a/services/api/src/typeDefs.js +++ b/services/api/src/typeDefs.js @@ -927,6 +927,8 @@ const typeDefs = gql` deleteEnvVariable(input: DeleteEnvVariableInput!): String addTask(input: TaskInput!): Task taskDrushArchiveDump(environment: Int!): Task + taskDrushSqlDump(environment: Int!): Task + taskDrushCacheClear(environment: Int!): Task taskDrushSqlSync( sourceEnvironment: Int! destinationEnvironment: Int! diff --git a/services/ui/src/components/AddTask/components/DrushCacheClear.js b/services/ui/src/components/AddTask/components/DrushCacheClear.js new file mode 100644 index 0000000000..6f0e7cc32b --- /dev/null +++ b/services/ui/src/components/AddTask/components/DrushCacheClear.js @@ -0,0 +1,96 @@ +import React from 'react'; +import { Mutation } from 'react-apollo'; +import gql from 'graphql-tag'; +import ReactSelect from 'react-select'; +import { bp, color, fontSize } from '../../../variables'; + +const taskDrushCacheClear = gql` + mutation taskDrushCacheClear( + $environment: Int! + ) { + taskDrushCacheClear( + environment: $environment + ) { + id + name + status + created + started + completed + remoteId + command + service + } + } +`; + +const DrushCacheClear = ({ + pageEnvironment, + onCompleted, + onError, +}) => ( + + {(taskDrushCacheClear, { loading, called, error, data }) => { + return ( + +
+ + +
+ + +
+ ); + }} +
+); + +export default DrushCacheClear; diff --git a/services/ui/src/components/AddTask/components/DrushSqlDump.js b/services/ui/src/components/AddTask/components/DrushSqlDump.js new file mode 100644 index 0000000000..0084bed049 --- /dev/null +++ b/services/ui/src/components/AddTask/components/DrushSqlDump.js @@ -0,0 +1,96 @@ +import React from 'react'; +import { Mutation } from 'react-apollo'; +import gql from 'graphql-tag'; +import ReactSelect from 'react-select'; +import { bp, color, fontSize } from '../../../variables'; + +const taskDrushSqlDump = gql` + mutation taskDrushSqlDump( + $environment: Int! + ) { + taskDrushSqlDump( + environment: $environment + ) { + id + name + status + created + started + completed + remoteId + command + service + } + } +`; + +const DrushSqlDump = ({ + pageEnvironment, + onCompleted, + onError, +}) => ( + + {(taskDrushSqlDump, { loading, called, error, data }) => { + return ( + +
+ + +
+ + +
+ ); + }} +
+); + +export default DrushSqlDump; diff --git a/services/ui/src/components/AddTask/index.js b/services/ui/src/components/AddTask/index.js index b410bff6e1..f04240542d 100644 --- a/services/ui/src/components/AddTask/index.js +++ b/services/ui/src/components/AddTask/index.js @@ -2,6 +2,8 @@ import React from 'react'; import ReactSelect from 'react-select'; import withLogic from './logic'; import DrushArchiveDump from './components/DrushArchiveDump'; +import DrushSqlDump from './components/DrushSqlDump'; +import DrushCacheClear from './components/DrushCacheClear'; import DrushRsyncFiles from './components/DrushRsyncFiles'; import DrushSqlSync from './components/DrushSqlSync'; import Empty from './components/Empty'; @@ -20,6 +22,8 @@ const AddTask = ({ }) => { const newTaskComponents = { DrushArchiveDump, + DrushSqlDump, + DrushCacheClear, DrushRsyncFiles, DrushSqlSync, Empty, diff --git a/services/ui/src/components/AddTask/logic.js b/services/ui/src/components/AddTask/logic.js index d7ad7313ab..9f94cf91ac 100644 --- a/services/ui/src/components/AddTask/logic.js +++ b/services/ui/src/components/AddTask/logic.js @@ -19,17 +19,26 @@ const withOptions = withProps(({ pageEnvironment }) => { return { options: [ { - label: 'Drush sql-sync', - value: 'DrushSqlSync' + label: 'Drush cache-clear', + value: 'DrushCacheClear' }, { - label: 'Drush archive-dump', - value: 'DrushArchiveDump' + label: 'Drush sql-sync', + value: 'DrushSqlSync' }, { label: 'Drush rsync', value: 'DrushRsyncFiles' + }, + { + label: 'Drush sql-dump', + value: 'DrushSqlDump' + }, + { + label: 'Drush archive-dump (D7 only)', + value: 'DrushArchiveDump' } + ] }; }); diff --git a/services/ui/src/components/NavTabs/index.js b/services/ui/src/components/NavTabs/index.js index 7c20bdcd46..1471bee3b0 100644 --- a/services/ui/src/components/NavTabs/index.js +++ b/services/ui/src/components/NavTabs/index.js @@ -19,11 +19,11 @@ const NavTabs = ({activeTab, environment}) => ( Backups - {/*
  • +
  • Tasks -
  • */} +