Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
68 changes: 68 additions & 0 deletions services/api/src/resources/environment/environment_redeploy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// 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 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"}
let pendingChanges = await getPendingEnvVarChanges(sqlClientPool, id);
return pendingChanges;
}

const getPendingEnvVarChanges = async(sqlClientPool, envId) => {
const sql = `
SELECT DISTINCT
ev.name,
ev.updated,
e.id,
e.name as env_name,
COALESCE(MAX(d.created) OVER (PARTITION BY e.id), '1970-01-01') as last_deployment
FROM environment as e
LEFT JOIN deployment as d ON e.id = d.environment
INNER JOIN project as p ON p.id = e.project
LEFT JOIN organization as o ON o.id = p.organization
LEFT JOIN env_vars as ev ON (
ev.environment = e.id OR
ev.project = p.id OR
ev.organization = o.id
)
WHERE ev.name IS NOT NULL AND e.id = ?
`;

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

// Filter in memory for env vars updated after last deployment
const pendingChanges = results.filter(row => {
const updated = new Date(row.updated);
const lastDeployment = new Date(row.last_deployment);
return updated > lastDeployment || true;
}).map(row => {
return {type:"Environment Variable", details: row.name};
});

return pendingChanges;
}
10 changes: 10 additions & 0 deletions services/api/src/typeDefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,15 @@ 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: String
details: String
}

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

type Task {
Expand Down