Skip to content

Commit

Permalink
Merge pull request #102 from razee-io/org_crud
Browse files Browse the repository at this point in the history
Org crud
  • Loading branch information
dalehille authored Jan 6, 2020
2 parents 30a0c1c + c7b907d commit ba6085e
Show file tree
Hide file tree
Showing 11 changed files with 530 additions and 3 deletions.
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ Razeedash-API is the interface used by
| S3_ACCESS_KEY_ID | if S3_ENDPOINT defined | n/a |
| S3_SECRET_ACCESS_KEY | if S3_ENDPOINT defined | n/a |
| S3_LOCATION_CONSTRAINT | no | 'us-standard'|
| ORG_ADMIN_KEY | no | n/a |

If S3_ENDPOINT is defined then encrypted cluster YAML is stored in S3 otherwise
it will be stored in the mongoDB.

ORG_ADMIN_KEY is required if you plan on adding organizations using the api/v2/orgs endpoint

### OS/X

gettext package is default on most Linux systems. If you are using OS/X for
Expand Down Expand Up @@ -86,6 +89,27 @@ data:
mongo_url: bW9uZ29kYjovL21vbmdvOjI3MDE3L3JhemVlZGFzaAo=
```
Add org_admin_key to the data section of `razeedash-secret` in order to control
organizations using the `api/v2/orgs` endpoint

<!--Markdownlint-disable MD013-->
```bash
echo -n abcdefghijklmnop012345678 | base64
# outputs YWJjZGVmZ2hpamtsbW5vcDAxMjM0NTY3OA==
```

```yaml
apiVersion: v1
kind: Secret
metadata:
name: razeedash-secret
namespace: razee
type: Opaque
data:
mongo_url: bW9uZ29kYjovL21vbmdvOjI3MDE3L3JhemVlZGFzaAo=
org_admin_key: YWJjZGVmZ2hpamtsbW5vcDAxMjM0NTY3OA==
```

If you are using your own managed mongodb system, make sure you
setup the `mongo_url` secret properly.

Expand Down
5 changes: 5 additions & 0 deletions app/routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const getOrg = require ('../utils/orgs').getOrg;
const Kube = require('./kube/kube.js');
const Install = require('./install');
const Clusters = require('./v2/clusters.js');
const Orgs = require('./v2/orgs.js');

router.use('/api/kube', Kube);
router.use(ebl(getBunyanConfig('/api/v2/')));
Expand All @@ -55,6 +56,10 @@ router.use(asyncHandler(async (req, res, next) => {
next();
}));

// the orgs routes should be above the razee-org-key checks since the user
// won't have a razee-org-key when creating an org for the first time.
router.use('/api/v2/orgs', Orgs);

router.use((req, res, next) => {
let orgKey = req.get('razee-org-key');
if(!orgKey){
Expand Down
152 changes: 152 additions & 0 deletions app/routes/v2/orgs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/**
* Copyright 2019 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 express = require('express');
const router = express.Router();
const asyncHandler = require('express-async-handler');
const ebl = require('express-bunyan-logger');
const _ = require('lodash');
const verifyAdminOrgKey = require('../../utils/orgs.js').verifyAdminOrgKey;
const uuid = require('uuid');

const getBunyanConfig = require('../../utils/bunyan.js').getBunyanConfig;

router.use(ebl(getBunyanConfig('razeedash-api/orgs')));

const createOrg = async(req, res) => {
const orgName = (req.body && req.body.name) ? req.body.name.trim() : null;

if(!orgName) {
req.log.warn(`An org name was not specified on route ${req.url}`);
return res.status(400).send( 'An org name is required' );
}

const Orgs = req.db.collection('orgs');
const foundOrg = await Orgs.findOne({'name': orgName});
if(foundOrg){
req.log.warn( 'The org name already exists' );
return res.status(400).send( 'This org already exists' );
}

const orgAdminKey = req.orgAdminKey; // this was set in verifyAdminOrgKey()
const orgApiKey = `orgApiKey-${uuid()}`;
try {
const insertedOrg = await Orgs.insertOne({
'_id': uuid(),
'name': orgName,
'orgKeys' : [ orgApiKey ],
'orgAdminKey': orgAdminKey,
'created': new Date(),
'updated': new Date()
});

if(insertedOrg.result.ok) {
return res.status(200).send( insertedOrg.ops[0] );
} else {
req.log.error(insertedOrg);
return res.status(500).send( 'Could not create the org' );
}
} catch (error) {
req.log.error(error);
return res.status(500).send( 'Error creating the org' );
}
};

const getOrgs = async(req, res) => {
try {
const Orgs = req.db.collection('orgs');

let orgsQuery = { orgAdminKey: req.orgAdminKey };
if(req.query && req.query.name) {
let orgsToSearch = [];
if(_.isArray(req.query.name)) {
orgsToSearch = req.query.name; // GET api/v2/orgs?name=org1&name=org2
} else {
orgsToSearch.push(req.query.name); // GET api/v2/orgs?name=org1
}
orgsQuery.name = { $in: orgsToSearch };
}

const foundOrgs = await Orgs.find(orgsQuery).toArray();
return res.status(200).send( foundOrgs );
} catch (error) {
req.log.error(error);
return res.status(500).send( 'Error searching for orgs' );
}
};

const updateOrg = async(req, res) => {
const existingOrgId = req.params.id;
const updates = req.body;

if (!updates) {
req.log.error('no message body was provided');
return res.status(400).send('Missing message body');
}

try {
const Orgs = req.db.collection('orgs');
const foundOrg = await Orgs.findOne({'_id': existingOrgId});
if(!foundOrg){
req.log.warn( 'The org was not found' );
return res.status(400).send( 'This org was not found' );
}

updates.updated = new Date();
const updatedOrg = await Orgs.updateOne({ _id: foundOrg._id }, { $set: updates } );
if(updatedOrg.result.ok) {
return res.status(200).send( 'success' );
} else {
req.log.error(updatedOrg);
return res.status(500).send( 'Could not update the org' );
}
} catch (error) {
req.log.error(error);
return res.status(500).send( 'Error updating the org' );
}
};


const deleteOrg = async(req, res) => {
const existingOrgId = req.params.id;
try {
const Orgs = req.db.collection('orgs');
const removedOrg = await Orgs.deleteOne({ '_id': existingOrgId } );
if(removedOrg.deletedCount) {
return res.status(200).send( 'success' );
} else {
req.log.error(removedOrg);
return res.status(500).send( 'The org could not be deleted' );
}
} catch (error) {
req.log.error(error);
return res.status(500).send( 'Error deleting the org' );
}
};

// /api/v2/orgs
router.post('/', asyncHandler(verifyAdminOrgKey), asyncHandler(createOrg));

// /api/v2/orgs?name=firstOrg&name=AnotherOrg
router.get('/', asyncHandler(verifyAdminOrgKey), asyncHandler(getOrgs));

// /api/v2/:id
router.put('/:id', asyncHandler(verifyAdminOrgKey), asyncHandler(updateOrg));

// /api/v2/:id
router.delete('/:id', asyncHandler(verifyAdminOrgKey), asyncHandler(deleteOrg));

module.exports = router;
Loading

0 comments on commit ba6085e

Please sign in to comment.