Note: The default ITS GitLab runner is a shared resource and is subject to slowdowns during heavy usage.
You can run your own GitLab runner that is dedicated just to your group if you need to avoid processing delays.

Commit 313609cb authored by Erik Schwartz's avatar Erik Schwartz 🉐
Browse files

Initial commit

parents
{
"extends": "strongloop",
"parserOptions": {
"ecmaVersion": 6
}
}
node_modules
settings/*.json
MIT License
Copyright (c) 2017 Erik Schwartz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# stop-sagemaker
Stop an AWS SageMaker notebook instance.
Tested with: [Node.js](https://nodejs.org/) v8 LTS and [AWS SDK for Javascript](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/index.html) (API Version: 2017-07-24)
## Set up environment
### Onetime install/configuration
1. Download and install Node.js LTS
2. Clone this repository
3. Install dependences: `cd stop-sagemaker && npm install`
4. [Optional] Copy the example file: `cp settings/demo.json.EXAMPLE settings/foo.json`
5. [Optional] Edit `settings/foo.json` to specify an AWS Region and IAM service account
### Export Node.js variables
```bash
_node=/path/to/node-v8.x.y
export NODE_PATH=${_node}/lib/node_modules
export PATH=${_node}/bin:$PATH
```
## Use it
### Run without args to see options
```bash
node app.js
Usage: app.js --name baz [--profile foo.json]
```
If `--profile` is not provided, the caller should export AWS environment variables:
* [Setting the AWS Region](https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-region.html)
* [Loading credentials from environment variables](https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/loading-node-credentials-environment.html)
This approach can be used for CI (e.g. Jenkins) build jobs.
---
# IAM policy
The IAM service account that you configure in `settings/foo.json` will need certain authorizations. Suggested starting point for an IAM policy:
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"sagemaker:StopNotebookInstance",
"sagemaker:DescribeNotebookInstance"
],
"Resource": "arn:aws:sagemaker:*:*:notebook-instance/*"
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": "sagemaker:ListNotebookInstances",
"Resource": "*"
}
]
}
```
'use strict';
// ----------------------------------------------------------------------------
// GLOBAL VARIABLES
// ----------------------------------------------------------------------------
const fs = require('fs');
const path = require('path');
const AWS = require('aws-sdk');
const argv = require('minimist')(process.argv.slice(2));
const defaultApiVersion = '2017-07-24';
var sagemaker;
// ----------------------------------------------------------------------------
// GENERAL FUNCTIONS
// ----------------------------------------------------------------------------
function printUsageAndExit() {
console.log('Usage: ' + path.basename(__filename) +
' --name baz [--profile foo.json]');
process.exit(1);
}
function auditCliArgs(o, arg, oppArg, type) {
// This function ensures that mutually exclusive args weren't given,
// that at least one of a required arg pair was given, and that args
// requiring a value have the expected type.
if (o.hasOwnProperty(arg) && o.hasOwnProperty(oppArg)) {
printUsageAndExit();
}
if (!o.hasOwnProperty(arg) && !o.hasOwnProperty(oppArg)) {
printUsageAndExit();
}
if (!type) {
return;
}
if (o.hasOwnProperty(arg) && typeof o[arg] === type) {
return;
} else if (o.hasOwnProperty(oppArg) && typeof o[oppArg] === type) {
return;
}
printUsageAndExit();
}
function suckInAwsProfile(inputFile) {
let profile = fs.readFileSync(inputFile, {encoding: 'utf8'});
let profileObj = JSON.parse(profile);
return profileObj;
}
function setupSdkClient(o) {
sagemaker = new AWS.SageMaker(o);
}
// ----------------------------------------------------------------------------
// STATE CHANGE FUNCTION
// ----------------------------------------------------------------------------
function bringDownInstance(nbName) {
let parms = {NotebookInstanceName: nbName};
sagemaker.stopNotebookInstance(parms, (err, data) => {
if (err) {
let down = 'Status (Stopped) not in ([InService])';
let stopping = 'Status (Stopping) not in ([InService])';
if (err.message.includes(down) || err.message.includes(stopping)) {
console.log('Instance is not running, no need to stop it');
} else {
throw err;
}
}
});
}
// ----------------------------------------------------------------------------
// MAIN LOGIC
// ----------------------------------------------------------------------------
auditCliArgs(argv, 'name', null, 'string');
// If a profile arg was provided, audit its type and read in the AWS
// credentials, region, and API version.
//
// If no profile arg was provided, we set API version based on the
// hardcoded default in this program. And we also rely on the caller to
// either 1) set AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_REGION
// in the environment; or 2) set up ~/.aws/config appropriately.
if (argv.profile) {
auditCliArgs(argv, 'profile', null, 'string');
setupSdkClient(suckInAwsProfile(argv.profile));
} else {
setupSdkClient({apiVersion: defaultApiVersion});
}
// Finally, perform the state change.
bringDownInstance(argv.name);
{
"name": "stop-sagemaker",
"version": "1.0.0",
"description": "Stop SageMaker instances",
"main": "app.js",
"dependencies": {
"aws-sdk": "^2.102.0",
"eslint": "^4.19.1",
"eslint-config-strongloop": "^2.1.0",
"minimist": "^1.2.0"
},
"devDependencies": {},
"scripts": {
"pretest": "eslint --ignore-path .gitignore .",
"test": "node -v"
},
"author": "Erik Schwartz (whatitis)",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://git.iq.it.umich.edu/whatitis/stop-sagemaker.git"
}
}
{
"accessKeyId": "KEY_HERE",
"apiVersion": "2016-11-15",
"region": "us-northwest-2",
"secretAccessKey": "SECRET_HERE"
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment