Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.up = function(knex) {
return knex.schema
.alterTable('env_vars', (table) => {
table.datetime('updated').notNullable().defaultTo(knex.fn.now());
})
.raw("UPDATE env_vars SET updated='1970-01-01 00:00:00'");
// Note, we do the above update so that all _existing_ env vars are
// not picked up as needing to be deployed (since we're using 'updated' to track new/updated vars)
// but any newly created items will get the _current_ date/time
};

/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.down = function(knex) {
return knex.schema
.alterTable('env_vars', (table) => {
table.dropColumn('updated');
})
};
5 changes: 5 additions & 0 deletions services/api/src/resolvers.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ const {
deleteEnvironmentService,
} = require('./resources/environment/resolvers');

const {
getPendingChangesByEnvironmentId,
} = require('./resources/environment/environment_redeploy')

const {
getDeployTargetConfigById,
getDeployTargetConfigsByProjectId,
Expand Down Expand Up @@ -522,6 +526,7 @@ async function getResolvers() {
facts: getFactsByEnvironmentId,
openshift: getOpenshiftByEnvironmentId,
kubernetes: getOpenshiftByEnvironmentId,
pendingChanges: getPendingChangesByEnvironmentId,
},
Organization: {
groups: getGroupsByOrganizationId,
Expand Down
3 changes: 3 additions & 0 deletions services/api/src/resources/env-variables/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,9 @@ export const addOrUpdateEnvVariableByName: ResolverFn = async (
}
}

// Let's set the updated value for the env var
updateData['updated'] = knex.fn.now();

const createOrUpdateSql = knex('env_vars')
.insert({
...updateData,
Expand Down
104 changes: 104 additions & 0 deletions services/api/src/resources/environment/environment_redeploy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// This file contains the logic to determine whether an environment requires a redeploy

import * as R from 'ramda';
import { sendToLagoonLogs } from '@lagoon/commons/dist/logs/lagoon-logger';
import { createRemoveTask, seedNamespace } from '@lagoon/commons/dist/tasks';
import { ResolverFn } from '..';
import { logger } from '../../loggers/logger';
import { isPatchEmpty, query, knex } from '../../util/db';
import { convertDateToMYSQLDateFormat } from '../../util/convertDateToMYSQLDateTimeFormat';
import { Helpers } from './helpers';
import { Sql } from './sql';
import { Sql as projectSql } from '../project/sql';
import { Helpers as projectHelpers } from '../project/helpers';
import { Helpers as openshiftHelpers } from '../openshift/helpers';
import { Helpers as organizationHelpers } from '../organization/helpers';
import { getFactFilteredEnvironmentIds } from '../fact/resolvers';
import { getUserProjectIdsFromRoleProjectIds } from '../../util/auth';
import { RemoveData, DeployType, AuditType } from '@lagoon/commons/dist/types';
import { AuditLog } from '../audit/types';


export const environmentPendingChangeTypes = {
ENVVAR: "ENVVAR",
};

export const getPendingChangesByEnvironmentId: ResolverFn = async(
{
id
},
_,
{ sqlClientPool, hasPermission },
) => {
// Note: as it stands, the only pending changes we have now have to do
// with env vars, but anything can be added in the form
// {type:"string", details:"string", date: "string"}
let pendingChanges = await getPendingEnvVarChanges(sqlClientPool, id);
return pendingChanges;
}

const getPendingEnvVarChanges = async(sqlClientPool, envId) => {
const sql = `
WITH last_completed AS (
SELECT COALESCE(MAX(d.created), TIMESTAMP('1970-01-01 00:00:00')) AS ts
FROM deployment d
WHERE d.environment = ? AND d.status = 'complete'
)
SELECT *
FROM (
-- Environment-scoped
SELECT
e.id AS env_id,
e.name AS env_name,
ev.name AS envvar_name,
ev.updated AS envvar_updated,
'Environment' AS envvar_source
FROM environment e
JOIN env_vars ev ON ev.environment = e.id
CROSS JOIN last_completed lc
WHERE e.id = ?
AND ev.name IS NOT NULL
AND ev.updated > lc.ts

UNION ALL

-- Project-scoped
SELECT
e.id, e.name,
ev.name, ev.updated,
'Project' AS envvar_source
FROM environment e
JOIN project p ON p.id = e.project
JOIN env_vars ev ON ev.project = p.id
CROSS JOIN last_completed lc
WHERE e.id = ?
AND ev.name IS NOT NULL
AND ev.updated > lc.ts

UNION ALL

-- Organization-scoped
SELECT
e.id, e.name,
ev.name, ev.updated,
'Organization' AS envvar_source
FROM environment e
JOIN project p ON p.id = e.project
JOIN organization o ON o.id = p.organization
JOIN env_vars ev ON ev.organization = o.id
CROSS JOIN last_completed lc
WHERE e.id = ?
AND ev.name IS NOT NULL
AND ev.updated > lc.ts
) AS allenvs
ORDER BY allenvs.envvar_updated DESC;
`;

const results = await query(sqlClientPool, sql, [envId, envId, envId, envId]);

const pendingChanges = results.map(row => {
return {type:environmentPendingChangeTypes.ENVVAR, details: `Variable name: ${row.envvarName} (source: ${row.envvarSource} )`, date: row.envvarUpdated};
});

return pendingChanges;
}
15 changes: 15 additions & 0 deletions services/api/src/typeDefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,20 @@ const typeDefs = gql`
openshiftProjectPattern: String @deprecated(reason: "No longer in use")
kubernetes: Kubernetes
kubernetesNamespacePattern: String @deprecated(reason: "No longer in use")
"""
Pending changes tell us if we need to redeploy an environment
"""
pendingChanges: [EnvironmentPendingChanges]
}

type EnvironmentPendingChanges {
type: EnvironmentPendingChangeType
details: String
date: String
}

enum EnvironmentPendingChangeType {
ENVVAR
}

type EnvironmentHitsMonth {
Expand Down Expand Up @@ -1005,6 +1019,7 @@ const typeDefs = gql`
scope: String
name: String
value: String
updated: String
}

type Task {
Expand Down
Loading