Skip to content

Commit

Permalink
Add first few functions
Browse files Browse the repository at this point in the history
  • Loading branch information
renatomassaro committed Apr 29, 2018
1 parent 80ab440 commit b5f18bb
Show file tree
Hide file tree
Showing 14 changed files with 772 additions and 5 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
_packages/
_dependencies/

42 changes: 37 additions & 5 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,38 @@
node {
echo 'wat'
sh "ls"
sh "uname -a"
sh "uptime"
node('master') {
stage('Setup env'){
TAG=sh(script: 'pwgen 5 1', returnStdout: true).trim()
sh "nohup python3.6 ~/start.py utils small-1 ${TAG} 5 &"
}
}

pipeline {
agent none
options {
skipDefaultCheckout()
timestamps()
}
stages {
stage("Checkout & deploy") {
when {
branch 'master'
}
agent {
node {
label "utils-small-1-${TAG}"
}
}
steps {
checkout scm
sh 'ls -lah'
sh 'python3.6 deploy.py'
}
}
}
post {
always {
node('master') {
sh "nohup python3.6 ~/stop.py ${TAG} &"
}
}
}
}
125 changes: 125 additions & 0 deletions deploy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import subprocess
import base64
import shutil
import json
import sys
import os
import boto3

lambda_client = boto3.client('lambda', region_name='us-east-1')
lambda_meta_deployer = 'lambdaMetaDeployer'

with_error = False

def bootstrap():
# Cleanup and prepare packaging folder
shutil.rmtree('_packages/')
os.makedirs('_packages', exist_ok=True)

shutil.rmtree('_dependencies/')
os.makedirs('_dependencies', exist_ok=True)

def scan_folders():
# Traverse the folder, detect functions and deploy each one individually
for root, dirs, files in os.walk('.', topdown=False):
if root.startswith('./.'):
continue

if root.startswith('./_'):
continue

if root == '.':
continue

# It's-a me, function!
if 'config.json' in files:
function_name = root[2:]

if 'requirements.txt' in files:
os.makedirs('_dependencies/{}'.format(function_name))

deploy(function_name)

if with_error:
raise Exception('Some functions were not deployed')

def deploy(function_name):
print('Packaging {}'.format(function_name))

with open(function_name + '/config.json') as config_file:
config = json.load(config_file)

validate_config(config)

print('Using config: {}'.format(config))

setup_dependencies(function_name)

create_package(function_name, config)

upsert_function(function_name, config)

def upsert_function(function_name, config):
with open('_packages/{}.zip'.format(function_name), 'rb') as package:
contents = package.read()
b64_zip_str = base64.b64encode(contents).decode('utf-8')

payload = {
'zip_file': b64_zip_str,
'config': config,
'target_function': function_name
}

resp = lambda_client.invoke(
FunctionName=lambda_meta_deployer,
Payload=json.dumps(payload)
)

if resp['ResponseMetadata']['HTTPStatusCode'] != 200:
print('Bad status code for {}: {}'.format(function_name, resp))
with_error = True
else:
print('{} deployed\n\n'.format(function_name))

def create_package(function_name, config):
# Zip application-specific stuff
cmd1 = 'cd {0}; zip -r9 ../_packages/{0}.zip *'.format(function_name)
subprocess.run(cmd1, check=True, shell=True)

# Add dependencies to package (if they exist)
if os.path.exists('_dependencies/{}/'.format(function_name)):
cmd2 = 'cd _dependencies/{0}; zip -r9 ../../_packages/{0}.zip *'.format(function_name)
subprocess.run(cmd2, check=True, shell=True)

if not os.stat('_packages/{0}.zip'.format(function_name)):
error('internal', 'error_creating_zip')

def setup_dependencies(function_name):
if os.path.exists('{}/requirements.txt'.format(function_name)):
cmd = 'pip3 install -r {0}/requirements.txt -t _dependencies/{0} '.format(function_name)
subprocess.run(cmd, check=True, shell=True)

def validate_config(config):
if not 'memory' in config:
error('config', 'missing_memory')

if config['memory'] % 128 not in [64, 0]:
error('config', 'invalid_memory')

if not 'timeout' in config:
error('config', 'missing_timeout')

if not 'handler' in config:
error('config', 'missing_handler')

def error(major, minor):
raise Exception(major + '_' + minor)

if __name__ == '__main__':
bootstrap()

if len(sys.argv) == 1:
scan_folders()
else:
for function_name in sys.argv[1:]:
deploy(function_name)
5 changes: 5 additions & 0 deletions jenkinsSlaveExpirator/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"memory": 128,
"timeout": 5,
"handler": "jse.lambda_handler"
}
42 changes: 42 additions & 0 deletions jenkinsSlaveExpirator/jse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from datetime import datetime
import boto3

ec2_client = boto3.client('ec2', region_name='us-east-1')

def lambda_handler(_event, _context):
query = ec2_client.describe_instances(
Filters=[
{
'Name': 'tag-key',
'Values': ['jenkins_slave_expiration_date']
},
{
'Name': 'instance-state-code',
'Values': ['0', '16']
}
],
)['Reservations']

print('Found {} matching instances...'.format(len(query)))

for instance in query:
if len(instance['Instances']) > 1:
print('Not sure what this means')

data = instance['Instances'][0]

expiration_date = None

for tag in data['Tags']:
if tag['Key'] == 'jenkins_slave_expiration_date':
expiration_date = datetime.strptime(tag['Value'], '%Y-%m-%d %H:%M:%S.%f')
break;

if datetime.utcnow() >= expiration_date:
instance_id = data['InstanceId']

print('Terminating instance {}'.format(instance_id))

ec2_client.terminate_instances(
InstanceIds=[instance_id]
)
5 changes: 5 additions & 0 deletions jenkinsSlaveLauncher/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"memory": 128,
"timeout": 35,
"handler": "jsl.lambda_handler"
}
Loading

0 comments on commit b5f18bb

Please sign in to comment.