Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add file storage to API and save task artifacts there #820

Merged
merged 17 commits into from Jan 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions node-packages/commons/src/jwt.js
Expand Up @@ -5,12 +5,18 @@ const jwt = require('jsonwebtoken');

/* ::
type Role = 'none' | 'admin' | 'drush';
type Permissions = {
projects: number[],
customers: number[],
};

type Payload = {|
userId: number,

role: Role,

permissions: Permissions,

// Issuer - Information on who created this token
iss: string,

Expand Down
14 changes: 14 additions & 0 deletions services/api-db/docker-entrypoint-initdb.d/00-tables.sql
Expand Up @@ -160,6 +160,14 @@ CREATE TABLE IF NOT EXISTS task (
remote_id varchar(50) NULL
);

CREATE TABLE IF NOT EXISTS s3_file (
id int NOT NULL auto_increment PRIMARY KEY,
filename varchar(100) NOT NULL,
s3_key text NOT NULL,
created datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted datetime NOT NULL DEFAULT '0000-00-00 00:00:00'
);

-- Junction Tables

CREATE TABLE IF NOT EXISTS project_notification (
Expand All @@ -186,3 +194,9 @@ CREATE TABLE IF NOT EXISTS project_user (
usid int REFERENCES user (id),
CONSTRAINT project_user_pkey PRIMARY KEY (pid, usid)
);

CREATE TABLE IF NOT EXISTS task_file (
tid int REFERENCES task (id),
fid int REFERENCES file (id),
CONSTRAINT task_file_pkey PRIMARY KEY (tid, fid)
);
21 changes: 21 additions & 0 deletions services/api-db/docker-entrypoint-initdb.d/01-migrations.sql
Expand Up @@ -568,6 +568,26 @@ CREATE OR REPLACE PROCEDURE
END;
$$

CREATE OR REPLACE PROCEDURE
convert_task_command_to_text()

BEGIN
DECLARE column_type varchar(50);

SELECT DATA_TYPE INTO column_type
FROM INFORMATION_SCHEMA.COLUMNS
WHERE
table_name = 'task'
AND table_schema = 'infrastructure'
AND column_name = 'command';

IF (column_type = 'varchar') THEN
ALTER TABLE task
MODIFY command text NOT NULL;
END IF;
END;
$$

DELIMITER ;

CALL add_production_environment_to_project();
Expand Down Expand Up @@ -597,6 +617,7 @@ CALL add_active_systems_task_to_project();
CALL add_default_value_to_task_status();
CALL add_scope_to_env_vars();
CALL add_deleted_to_environment_backup();
CALL convert_task_command_to_text();

-- Drop legacy SSH key procedures
DROP PROCEDURE IF EXISTS CreateProjectSshKey;
Expand Down
8 changes: 6 additions & 2 deletions services/api/package.json
Expand Up @@ -19,6 +19,9 @@
"license": "MIT",
"dependencies": {
"@lagoon/commons": "4.0.0",
"apollo-server-express": "^2.2.5",
"aws-sdk": "^2.378.0",
"axios": "^0.18.0",
"body-parser": "^1.18.2",
"camelcase-keys": "^4.2.0",
"compression": "^1.7.1",
Expand All @@ -28,16 +31,17 @@
"elasticsearch": "^15.0.0",
"es7-sleep": "^1.0.0",
"express": "^4.16.1",
"express-graphql": "^0.6.11",
"flow-remove-types": "^1.2.3",
"got": "^9.2.2",
"graphql": "^0.13.2",
"graphql-iso-date": "^3.5.0",
"graphql-list-fields": "^2.0.2",
"graphql-rabbitmq-subscriptions": "^1.1.0",
"graphql-subscriptions": "^1.0.0",
"graphql-tools": "^2.5.0",
"jsonwebtoken": "^8.0.1",
"jwk-to-pem": "^2.0.0",
"keycloak-admin": "^1.8.0",
"keycloak-connect": "^4.5.0",
"knex": "^0.14.3",
"mariasql": "^0.2.6",
"moment": "^2.22.2",
Expand Down
67 changes: 67 additions & 0 deletions services/api/src/apolloServer.js
@@ -0,0 +1,67 @@
// @flow

const R = require('ramda');
const { ApolloServer, AuthenticationError } = require('apollo-server-express');
const { getCredentialsForLegacyToken, getCredentialsForKeycloakToken } = require('./util/auth');
const logger = require('./logger');
const typeDefs = require('./typeDefs');
const resolvers = require('./resolvers');

const apolloServer = new ApolloServer({
typeDefs,
resolvers,
debug: process.env.NODE_ENV === 'development',
subscriptions: {
onConnect: async (connectionParams, webSocket) => {
const token = R.prop('authToken', connectionParams);
let credentials;

if (!token) {
throw new AuthenticationError('Auth token missing.');
}

try {
credentials = await getCredentialsForKeycloakToken(token);
} catch (e) {
// It might be a legacy token, so continue on.
logger.debug(`Keycloak token auth failed: ${e.message}`);
}

try {
if (!credentials) {
credentials = await getCredentialsForLegacyToken(token);
}
} catch (e) {
throw new AuthenticationError(e.message);
}

// Add credentials to context.
return { credentials };
},
},
context: ({ req, connection }) => {
// Websocket requests
if (connection) {
// onConnect must always provide connection.context.
return connection.context;
}

// HTTP requests
if (!connection) {
return {
// Express middleware must always provide req.credentials.
credentials: req.credentials,
};
}
},
formatError: (error) => {
logger.warn(error.message);
return {
message: error.message,
locations: error.locations,
path: error.path,
};
},
});

module.exports = apolloServer;
69 changes: 23 additions & 46 deletions services/api/src/app.js
Expand Up @@ -7,58 +7,35 @@ const cors = require('cors');
const { json } = require('body-parser');
const logger = require('./logger');
const createRouter = require('./routes');
const { authKeycloakMiddleware } = require('./authKeycloakMiddleware');
const { createAuthMiddleware } = require('./authMiddleware');
const authMiddleware = require('./authMiddleware');
const apolloServer = require('./apolloServer');

/* ::
type CreateAppArgs = {
store?: Object,
jwtSecret: string,
jwtAudience: string,
};
*/
const app = express();

const createApp = (args /* : CreateAppArgs */) => {
const {
// store,
jwtSecret,
jwtAudience,
} = args;
const app = express();
// Use compression (gzip) for responses.
app.use(compression());

// Use compression (gzip) for responses.
app.use(compression());
// Automatically decode json.
app.use(json());

// Automatically decode json.
app.use(json());
// Add custom configured logger (morgan through winston).
app.use(
morgan('combined', {
stream: {
write: message => logger.info(message),
},
}),
);

// Add custom configured logger (morgan through winston).
app.use(
morgan('combined', {
stream: {
write: message => logger.info(message),
},
}),
);
// TODO: Restrict requests to lagoon domains?
app.use(cors());

// TODO: Restrict requests to lagoon domains?
app.use(cors());
// $FlowFixMe
app.use(authMiddleware);

// $FlowFixMe
app.use(authKeycloakMiddleware());
// Add routes.
app.use('/', createRouter());

app.use(
createAuthMiddleware({
baseUri: 'http://auth-server:3000',
jwtSecret,
jwtAudience,
}),
);
apolloServer.applyMiddleware({ app });

// Add routes.
app.use('/', createRouter());

return app;
};

module.exports = createApp;
module.exports = app;
125 changes: 0 additions & 125 deletions services/api/src/authKeycloakMiddleware.js

This file was deleted.