Skip to content

Commit

Permalink
Merge branch 'master' into optional-data_location
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-topchiev committed May 19, 2021
2 parents 29cf5a8 + 5581646 commit 8be22ca
Show file tree
Hide file tree
Showing 39 changed files with 1,397 additions and 840 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"parserOptions": {
"ecmaVersion": 9,
"sourceType": "module"
"sourceType": "script"
},
"env": {
"node": true,
Expand Down
9 changes: 8 additions & 1 deletion app/apollo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ const logger = bunyan.createLogger(bunyanConfig);
const promClient = require('prom-client');
const createMetricsPlugin = require('apollo-metrics');
const apolloMetricsPlugin = createMetricsPlugin(promClient.register);
const apolloMaintenancePlugin = require('./maintenance/maintenanceModePlugin.js');
const { GraphqlPubSub } = require('./subscription');
const initModule = require(`./init.${AUTH_MODEL}`);
const conf = require('../conf.js').conf;

const pubSub = GraphqlPubSub.getInstance();

Expand Down Expand Up @@ -121,12 +123,17 @@ const createApolloServer = () => {
logger.info('Adding metrics plugin: apollo-metrics');
customPlugins.push(apolloMetricsPlugin);
}
if(conf.maintenance.flag && conf.maintenance.key) {
logger.info('Adding graphql plugin apolloMaintenancePlugin to disable all mutations');
customPlugins.push(apolloMaintenancePlugin);
}

logger.info(customPlugins, 'Apollo server custom plugin are loaded.');
const server = new ApolloServer({
introspection: true, // set to true as long as user has valid token
plugins: customPlugins,
tracing: process.env.GRAPHQL_ENABLE_TRACING === 'true',
playground: process.env.GRAPHQL_ENABLE_PLAYGROUND === 'false',
playground: process.env.GRAPHQL_ENABLE_PLAYGROUND === 'true',
typeDefs,
resolvers,
schemaDirectives: {
Expand Down
39 changes: 39 additions & 0 deletions app/apollo/maintenance/maintenanceModePlugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Copyright 2021 IBM Corp. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

const { RazeeMaintenanceMode } = require ('../resolvers/common');
const { maintenanceMode, maintenanceMessage } = require('../../utils/maintenance');
const conf = require('../../conf.js').conf;

const apolloMaintenancePlugin = {
requestDidStart() {
return {
// https://www.apollographql.com/docs/apollo-server/integrations/plugins/#responseforoperation
// The responseForOperation event is fired immediately before GraphQL execution would take place.
// If its return value resolves to a non-null GraphQLResponse, that result is used instead of executing the query.
async responseForOperation(context) {
if(context.operation && context.operation.operation && context.operation.operation === 'mutation') {
if(await maintenanceMode(conf.maintenance.flag, conf.maintenance.key)) {
throw new RazeeMaintenanceMode(maintenanceMessage, context);
}
}
return;
}
};
}
};

module.exports = apolloMaintenancePlugin;
8 changes: 7 additions & 1 deletion app/apollo/models/const.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const RESOURCE_MAX_TOTAL_LIMIT = process.env.RESOURCE_MAX_TOTAL_LIMIT || 500000;
const CHANNEL_MAX_TOTAL_LIMIT = process.env.CHANNEL_MAX_TOTAL_LIMIT || 1000;
const CHANNEL_VERSION_MAX_TOTAL_LIMIT = process.env.CHANNEL_VERSION_MAX_TOTAL_LIMIT || 1000;
const SUBSCRIPTION_MAX_TOTAL_LIMIT = process.env.SUBSCRIPTION_MAX_TOTAL_LIMIT || 1000;
const SERVICE_SUBSCRIPTION_MAX_TOTAL_LIMIT = process.env.SERVICE_SUBSCRIPTION_MAX_TOTAL_LIMIT || 100;

// Set Yaml file maximum size allowed in MB
const CHANNEL_VERSION_YAML_MAX_SIZE_LIMIT_MB = process.env.CHANNEL_VERSION_YAML_MAX_SIZE_LIMIT_MB || 2;
Expand Down Expand Up @@ -54,6 +55,10 @@ const SUBSCRIPTION_LIMITS = {
MAX_TOTAL: SUBSCRIPTION_MAX_TOTAL_LIMIT, // max total subscriptions allowed per account
};

const SERVICE_SUBSCRIPTION_LIMITS = {
MAX_TOTAL: SERVICE_SUBSCRIPTION_MAX_TOTAL_LIMIT, // max total service subscriptions allowed per account
};

const CLUSTER_REG_STATES = {
REGISTERING: 'registering', // cluster db entry is created
PENDING: 'pending', // razeedeploy-job yaml is downloaded, maybe already applied to the target cluster
Expand Down Expand Up @@ -82,4 +87,5 @@ const DIRECTIVE_LIMITS = {
// console.log('NODE_ENV: ' + config.util.getEnv('NODE_ENV') + `, DIRECTIVE_LIMITS: ${JSON.stringify(DIRECTIVE_LIMITS)}`);

module.exports = { RDD_STATIC_ARGS, ACTIONS, TYPES, AUTH_MODELS, AUTH_MODEL, SECRET, GRAPHQL_PATH , APOLLO_STREAM_SHARDING,
CLUSTER_LIMITS, CLUSTER_REG_STATES, CLUSTER_STATUS, RESOURCE_LIMITS, CHANNEL_LIMITS, CHANNEL_VERSION_LIMITS, SUBSCRIPTION_LIMITS, CHANNEL_VERSION_YAML_MAX_SIZE_LIMIT_MB, DIRECTIVE_LIMITS};
CLUSTER_LIMITS, CLUSTER_REG_STATES, CLUSTER_STATUS, RESOURCE_LIMITS, CHANNEL_LIMITS, CHANNEL_VERSION_LIMITS, SUBSCRIPTION_LIMITS,
SERVICE_SUBSCRIPTION_LIMITS, CHANNEL_VERSION_YAML_MAX_SIZE_LIMIT_MB, DIRECTIVE_LIMITS};
2 changes: 2 additions & 0 deletions app/apollo/models/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const Cluster = require('./cluster');
const Organization = require('./organization');
const Channel = require('./channel');
const Subscription = require('./subscription');
const ServiceSubscription = require('./serviceSubscription');
const DeployableVersion = require('./deployableVersion');
const ResourceYamlHist = require('./resourceYamlHist');
const Group = require('./group');
Expand Down Expand Up @@ -77,6 +78,7 @@ const models = {
Channel,
Group,
Subscription,
ServiceSubscription,
DeployableVersion,
ResourceYamlHist,
dbConnections: []
Expand Down
23 changes: 23 additions & 0 deletions app/apollo/models/serviceSubscription.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Copyright 2020 IBM Corp. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

const mongoose = require('mongoose');
const ServiceSubscriptionSchema = require('./serviceSubscription.schema');
ServiceSubscriptionSchema.plugin(require('mongoose-lean-virtuals'));

const ServiceSubscription = mongoose.model('ServiceSubscription', ServiceSubscriptionSchema);

module.exports = ServiceSubscription;
80 changes: 80 additions & 0 deletions app/apollo/models/serviceSubscription.schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* Copyright 2020 IBM Corp. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

const mongoose = require('mongoose');

const ServiceSubscriptionSchema = new mongoose.Schema({
_id: {
type: String,
},
org_id: {
type: String,
alias: 'orgId',
},
clusterOrgId: {
type: String,
},
name: {
type: String,
},
uuid: {
type: String,
},
groups: [
{
type: String,
}
],
clusterId: {
type: String,
},
channel_uuid: {
type: String,
alias: 'channelUuid',
},
channelName: {
type: String,
},
version: {
type: String,
},
version_uuid: {
type: String,
alias: 'versionUuid',
},
owner: {
type: String,
},
kubeOwnerName: {
type: String,
},
created: {
type: Date,
default: Date.now,
},
updated: {
type: Date,
default: Date.now,
},
}, {
collection: 'serviceSubscriptions',
strict:'throw',
});

ServiceSubscriptionSchema.index({ version_uuid: 1 });
ServiceSubscriptionSchema.index({ org_id: 1 });

module.exports = ServiceSubscriptionSchema;
13 changes: 11 additions & 2 deletions app/apollo/models/user.local.schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ UserLocalSchema.statics.createToken = async (user, secret, expiresIn) => {
role: user.meta.orgs[0].role,
org_id: user.meta.orgs[0]._id,
meta: user.meta,
org_admin: user.org_admin
};
return jwt.sign(claim, secret, {
expiresIn,
Expand Down Expand Up @@ -205,6 +206,10 @@ UserLocalSchema.statics.signIn = async (models, login, password, secret, context
logger.warn({ req_id: context.req_id }, 'Invalid password.');
throw new AuthenticationError('Invalid password.');
}
const storedAdminKey = process.env.ORG_ADMIN_KEY;
if (storedAdminKey) {
user.org_admin = storedAdminKey === context.req.headers['org-admin-key'];
}
return { token: models.User.createToken(user, secret, '240m') };
};

Expand Down Expand Up @@ -284,7 +289,9 @@ UserLocalSchema.statics.isAuthorizedBatch = async function(me, orgId, objectArra
}
return new Array(objectArray.length).fill(result);
}

if (me.org_admin) {
return new Array(objectArray.length).fill(true);
}
const orgMeta = me.meta.orgs.find((o)=>{
return (o._id == orgId);
});
Expand Down Expand Up @@ -316,7 +323,9 @@ UserLocalSchema.statics.isAuthorized = async function(me, orgId, action, type, a
// say no for if it is cluster facing api
return false;
}

if (me.org_admin) {
return true;
}
const orgMeta = me.meta.orgs.find((o)=>{
return (o._id == orgId);
});
Expand Down
12 changes: 11 additions & 1 deletion app/apollo/resolvers/channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -416,11 +416,15 @@ const channelResolvers = {
const channel_uuid = channel.uuid;

const subCount = await models.Subscription.count({ org_id, channel_uuid });

if(subCount > 0){
throw new RazeeValidationError(context.req.t('{{subCount}} subscription(s) depend on this configuration channel. Please update/remove them before removing this configuration channel.', {'subCount':subCount}), context);
}

const serSubCount = await models.ServiceSubscription.count({ channel_uuid });
if(serSubCount > 0){
throw new RazeeValidationError(context.req.t('{{serSubCount}} service subscription(s) depend on this channel. Please have tem updated/removed before removing this channel.', {'serSubCount':serSubCount}), context);
}

// deletes the linked deployableVersions in s3
var versionsToDeleteFromS3 = await models.DeployableVersion.find({ org_id, channel_id: channel.uuid, location: 's3', });
const limit = pLimit(5);
Expand Down Expand Up @@ -457,10 +461,16 @@ const channelResolvers = {
if(!deployableVersionObj){
throw new NotFoundError(context.req.t('version uuid "{{uuid}}" not found', {'uuid':uuid}), context);
}

const subCount = await models.Subscription.count({ org_id, version_uuid: uuid });
if(subCount > 0){
throw new RazeeValidationError(context.req.t('{{subCount}} subscriptions depend on this configuration channel version. Please update/remove them before removing this configuration channel version.', {'subCount':subCount}), context);
}
const serSubCount = await models.ServiceSubscription.count({ version_uuid: uuid });
if(serSubCount > 0){
throw new RazeeValidationError(context.req.t('{{serSubCount}} service subscriptions depend on this channel version. Please have them updated/removed before removing this channel version.', {'serSubCount':serSubCount}), context);
}

const channel_uuid = deployableVersionObj.channel_id;
const channel = await models.Channel.findOne({ uuid: channel_uuid, org_id });
if(!channel){
Expand Down
9 changes: 8 additions & 1 deletion app/apollo/resolvers/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,16 @@ class RazeeQueryError extends BasicRazeeError {
}
}

class RazeeMaintenanceMode extends BasicRazeeError {
constructor(message, context) {
const name = 'MaintenanceMode';
super(message, context, name);
}
}

module.exports = {
whoIs, validAuth,
getAllowedChannels, filterChannelsToAllowed, getAllowedSubscriptions, filterSubscriptionsToAllowed,
BasicRazeeError, NotFoundError, RazeeValidationError, RazeeForbiddenError, RazeeQueryError,
BasicRazeeError, NotFoundError, RazeeValidationError, RazeeForbiddenError, RazeeQueryError, RazeeMaintenanceMode,
validClusterAuth, getAllowedGroups, getGroupConditions, getGroupConditionsIncludingEmpty, applyClusterInfoOnResources,
};
2 changes: 2 additions & 0 deletions app/apollo/resolvers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const groupResolvers = require('./group');
const clusterResolvers = require('./cluster');
const channelResolvers = require('./channel');
const subscriptionResolvers = require('./subscription');
const serviceResolvers = require('./serviceSubscription');
const organizationResolvers = require('./organization');

const customScalarResolver = {
Expand All @@ -38,6 +39,7 @@ const resolvers = [
groupResolvers,
clusterResolvers,
subscriptionResolvers,
serviceResolvers,
channelResolvers,
];

Expand Down
Loading

0 comments on commit 8be22ca

Please sign in to comment.