Last active
August 25, 2016 15:07
-
-
Save Miciah/d149f18d873b79763b72 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/ruby | |
require 'aws-sdk' | |
require 'getoptlong' | |
require 'net/ssh' | |
require 'parseconfig' | |
REGIONS = { | |
'us-east-1' => 'N. Virginia', | |
'us-west-2' => 'Oregon', | |
'us-west-1' => 'N. California', | |
'eu-west-1' => 'Ireland', | |
'eu-central-1' => 'Frankfurt', | |
'ap-southeast-1' => 'Singapore', | |
'ap-southeast-2' => 'Sydney', | |
'ap-northeast-1' => 'Tokyo', | |
'sa-east-1' => 'Sao Paulo', | |
} | |
def print_usage | |
puts <<USAGE | |
== Synopsis | |
launch-ose3-ami: Launch, configure, or terminate an OpenShift Enterprise v3 AMI. | |
== Usage | |
launch-ose3-ami launch <instance_name> [options] | |
launch-ose3-ami configure <instance_name> [options] | |
launch-ose3-ami terminate <instance_name> | |
== List of options for "launch" and "configure": | |
-c|--credentials file AWS credentials file (optional, default: ~/.awscred) | |
-i|--image image Image (AMI) to launch (optional, default: latest) | |
-k|--key key SSH key to inject into the instance (optional, default: libra) | |
-r|--region region Region to launch the instance in (optional, default: us-east-1) | |
-b|--bucket bucket S3 bucket for image registry (optional, default: none) | |
-s|--size size Size of instance to launch (optional, default: t2.large) | |
-v|--vpc vpc VPC to use for new instance (optional, default: devenv) | |
-g|--security-group secgroup Security group(s) for new instance (optional, default: default) | |
-u|--subnet subnet Subnet to use for new instance (optional, default: subnet-cf57c596) | |
-?|--help Print this message | |
USAGE | |
end | |
def fail *message | |
puts message | |
exit 1 | |
end | |
ARGS = {} | |
$AWS_CONF = nil | |
$COMMAND = nil | |
$INSTANCE = nil | |
def parse_args | |
opts = GetoptLong.new( | |
['--credentials', '-c', GetoptLong::OPTIONAL_ARGUMENT], | |
['--image', '-i', GetoptLong::OPTIONAL_ARGUMENT], | |
['--key', '-k', GetoptLong::OPTIONAL_ARGUMENT], | |
['--name', '-n', GetoptLong::REQUIRED_ARGUMENT], | |
['--region', '-r', GetoptLong::OPTIONAL_ARGUMENT], | |
['--bucket', '-b', GetoptLong::OPTIONAL_ARGUMENT], | |
['--size', '-s', GetoptLong::OPTIONAL_ARGUMENT], | |
['--vpc', '-v', GetoptLong::OPTIONAL_ARGUMENT], | |
['--security-group', '-g', GetoptLong::OPTIONAL_ARGUMENT], | |
['--subnet', '-u', GetoptLong::OPTIONAL_ARGUMENT], | |
['--help', '-?', GetoptLong::NO_ARGUMENT] | |
) | |
begin | |
opts.each{|k,v| ARGS[k] = v} | |
rescue GetoptLong::Error | |
print_usage | |
exit 255 | |
end | |
if ARGS['--help'] | |
print_usage | |
exit 0 | |
end | |
ARGS['--credentials'] ||= '~/.awscred' | |
ARGS['--key'] ||= 'libra' | |
ARGS['--region'] ||= 'us-east-1' | |
#ARGS['--bucket'] ||= 'mmasters' | |
ARGS['--size'] ||= 't2.large' | |
ARGS['--security-group'] ||= 'default' | |
ARGS['--subnet'] ||= 'subnet-cf57c596' | |
ARGS['--vpc'] ||= 'devenv' | |
# TODO: Validate ARGS['--size']. | |
if !REGIONS.include?(ARGS['--region']) | |
fail "Invalid region: #{ARGS['--region']}.", | |
'The following regions are recognised:', | |
REGIONS.map {|k,v| "#{k} (#{v})"} | |
end | |
ARGS['--credentials'] = File.expand_path(ARGS['--credentials']) | |
if !File.exists?(ARGS['--credentials']) | |
fail "Credentials file not found: #{ARGS['--credentials']}." | |
end | |
$AWS_CONF = ParseConfig.new(ARGS['--credentials']) | |
$COMMAND = ARGV.shift | |
$INSTANCE = ARGV.shift | |
if $INSTANCE.nil? || $INSTANCE.empty? | |
fail 'You must specify a non-empty instance name.' | |
end | |
if !ARGV.empty? | |
print_usage | |
exit 255 | |
end | |
end | |
def get_ec2_client | |
puts 'Setting up AWS connection...' | |
client = Aws::EC2::Client.new( | |
access_key_id: $AWS_CONF['AWSAccessKeyId'], | |
secret_access_key: $AWS_CONF['AWSSecretKey'], | |
region: ARGS['--region'] | |
) | |
resource = Aws::EC2::Resource.new(client: client) | |
[client, resource] | |
end | |
def launch_instance instance_name | |
client, resource = get_ec2_client | |
if ARGS['--image'].nil? | |
puts 'Determining image name...' | |
images = [] | |
resource.images({filters: [{name: 'name', values: ['devenv-rhel7_*']}]}). | |
each do |image| | |
images << image | |
end | |
ARGS['--image'] = images. | |
select {|image| image.state == 'available'}. | |
sort_by {|image| image.name[/.*_(\d)+/, 1]}. | |
last.id | |
end | |
if ARGS['--vpc'][0,4] != 'vpc-' | |
resource.vpcs.each do |vpc| | |
if vpc.tags.any? {|tag| tag.key == 'Name' && tag.value == ARGS['--vpc']} | |
ARGS['--vpc'] = vpc.id | |
break | |
end | |
end | |
end | |
if ARGS['--vpc'][0,4] != 'vpc-' | |
fail "Unrecognised VPC: #{ARGS['--vpc']}" | |
end | |
secgroups, resolve = ARGS['--security-group'].split(',').partition do |sg| | |
sg[0,3] == 'sg-' | |
end | |
if !resolve.empty? | |
resource. | |
security_groups({filters: [{name: 'vpc-id', values: [ARGS['--vpc']]}]}). | |
each do |sg| | |
secgroups << sg.id if resolve.delete sg.group_name | |
end | |
end | |
if !resolve.empty? | |
fail 'Unrecognised security groups:', resolve | |
end | |
puts "Launching instance #{instance_name} from image #{ARGS['--image']}" + | |
" with size #{ARGS['--size']} and key #{ARGS['--key']}" + | |
" in region #{ARGS['--region']}" + | |
(ARGS['--bucket'] ? " using bucket #{ARGS['--bucket']}" : '') + | |
" and VPC #{ARGS['--vpc']}" + | |
" with security groups #{secgroups.join(', ')}..." | |
instances = resource.create_instances({ | |
min_count: 1, | |
max_count: 1, | |
image_id: ARGS['--image'], | |
instance_type: ARGS['--size'], | |
network_interfaces: [ | |
{ | |
subnet_id: ARGS['--subnet'], | |
groups: secgroups, | |
device_index: 0, | |
} | |
], | |
key_name: ARGS['--key'], | |
}) | |
puts 'Tagging instance names...' | |
instances.each do |instance| | |
instance.create_tags({tags: [key: 'Name', value: instance_name]}) | |
end | |
puts 'Waiting for instances to be available...' | |
begin | |
client.wait_until(:instance_running, | |
instance_ids: instances.map {|instance| instance.id}) | |
rescue Aws::Waiters::Errors::WaiterFailed | |
$stderr.puts 'Failed to create instance.' | |
exit 1 | |
end | |
puts 'Waiting for instances to have a public DNS entry...' | |
instances.each {|instance| sleep 1 while instance.public_dns_name.nil?} | |
instances.each {|instance| instance.reload} | |
instances | |
end | |
def find_instance instance_name | |
_, resource = get_ec2_client | |
puts "Looking up instance #{instance_name}..." | |
instances = [] | |
resource.instances({filters: [{name: 'tag:Name', values: [instance_name]}]}). | |
each {|instance| instances << instance} | |
instances | |
end | |
def configure_instance instance | |
puts "Configuring instance #{instance.public_dns_name} (#{instance.id})..." | |
docker_configuration = "version: 0.1 | |
log: | |
level: debug | |
http: | |
addr: :5000 | |
storage: | |
cache: | |
layerinfo: inmemory | |
s3: | |
accesskey: #{$AWS_CONF['AWSAccessKeyId']} | |
secretkey: #{$AWS_CONF['AWSSecretKey']} | |
region: #{ARGS['--region']} | |
bucket: #{ARGS['--bucket']} | |
encrypt: true | |
secure: true | |
v4auth: true | |
rootdirectory: /registry | |
middleware: | |
repository: | |
- name: openshift | |
" if ARGS['--bucket'] | |
retries = 0 | |
begin | |
Net::SSH.start(instance.public_dns_name, 'root') do |session| | |
puts ' Creating the master configuration...' | |
session.exec! 'openshift start master --write-config=/openshift.local.config/master' | |
puts ' Creating the node configuration...' | |
session.exec! "oadm create-node-config --node-dir=/openshift.local.config/node-#{instance.private_dns_name} --node=#{instance.private_dns_name} --hostnames=#{instance.private_dns_name},#{instance.private_ip_address},#{instance.public_dns_name},#{instance.public_ip_address} --certificate-authority=/openshift.local.config/master/ca.crt --signer-cert=/openshift.local.config/master/ca.crt --signer-key=/openshift.local.config/master/ca.key --signer-serial=/openshift.local.config/master/ca.serial.txt --node-client-certificate-authority=/openshift.local.config/master/ca.crt" | |
puts ' Modifying openshift unit file to use master and node configuration...' | |
session.exec! "sed -i -e '/ExecStart/ s|$| --node-config=/openshift.local.config/node-#{instance.private_dns_name}/node-config.yaml --master-config=/openshift.local.config/master/master-config.yaml|' /usr/lib/systemd/system/openshift.service" | |
puts ' Fixing hostname in the openshift unit file...' | |
session.exec! "sed -i -e 's/ec2\\(-[0-9]\\+\\)\\{4\\}.compute-1.amazonaws.com/#{instance.public_dns_name}/' /usr/lib/systemd/system/openshift.service" | |
puts ' Reloading systemd...' | |
session.exec! 'systemctl daemon-reload' | |
puts ' Starting the openshift service...' | |
session.exec! 'systemctl start openshift' | |
puts ' Waiting for the openshift service to start...' | |
session.exec! 'while ! oc status >& /dev/null; do sleep 1; done' | |
puts ' Configuring roles...' | |
session.exec! 'oadm policy add-role-to-user system:registry reguser' | |
puts ' Deploying the image registry...' | |
session.exec! 'oadm registry --config=/openshift.local.config/master/admin.kubeconfig --credentials=/openshift.local.config/master/openshift-registry.kubeconfig' | |
puts ' Creating service account for the registry...' | |
session.exec! 'oc create sa registry' | |
puts ' Adding registry service account to privileged SCC...' | |
session.exec! 'oc patch scc/privileged --patch=\'[{"op":"add","path":"/users/-","value":"system:serviceaccount:default:registry"}]\' --type=json' | |
if ARGS['--bucket'].nil? | |
puts ' Skipping image-registry configuration because no bucket was specified.' | |
else | |
puts ' Scaling image registry down...' | |
session.exec! 'oc scale --replicas=0 dc/docker-registry' | |
puts ' Writing out image-registry configuration file...' | |
session.exec! "cat > /root/config.yml <<EOF | |
#{docker_configuration} | |
EOF" | |
puts ' Adding secret for image-registry configuration...' | |
session.exec! 'oc secrets new dockerregistry /root/config.yml' | |
puts ' Adding secrets volume with new secret to the image registry...' | |
session.exec! 'oc volume dc/docker-registry --add --name=dockersecrets -m /etc/registryconfig --type=secret --secret-name=dockerregistry' | |
puts ' Configuring image registry to use new configuration file...' | |
session.exec! 'oc env dc/docker-registry REGISTRY_CONFIGURATION_PATH=/etc/registryconfig/config.yml' | |
puts ' Scaling image registry back up...' | |
session.exec! 'oc scale --replicas=1 dc/docker-registry' | |
end | |
puts ' Exposing the registry...' | |
session.exec! 'oc expose service docker-registry && oc patch routes/docker-registry -p \'{"spec":{"tls":{"termination":"edge","insecureEdgeTerminationPolicy":"Allow"}}}\'' | |
puts ' Importing Centos 7 image streams...' | |
session.exec! 'oc create -f https://raw.githubusercontent.com/openshift/origin/master/examples/image-streams/image-streams-centos7.json -n openshift' | |
puts ' Creating service account for the router...' | |
session.exec! 'oc create sa router' | |
puts ' Adding router service account to privileged SCC...' | |
#session.exec! 'oc patch scc/privileged --patch=\'[{"op":"add","path":"/users/-","value":"system:serviceaccount:default:router"}]\' --type=json' | |
session.exec! 'oadm policy add-scc-to-user privileged system:serviceaccount:default:router' | |
puts ' Fixing builder service account...' | |
#session.exec! 'export OC_EDITOR=\'sed -i -e "/system:serviceaccount:openshift-infra:build-controller/ s/openshift-infra/default/"\'; oc edit scc privileged' | |
#session.exec! 'oc patch scc/privileged --patch=\'[{"op":"test","path":"/users/0","value":"system:serviceaccount:openshift-infra:build-controller"},{"op":"replace","path":"/users/0","value":"system:serviceaccount:default:build-controller"}]\' --type=json' | |
session.exec! 'oadm policy add-scc-to-user privileged system:serviceaccount:openshift-infra:build-controller' | |
session.exec! 'oadm policy add-scc-to-user privileged system:serviceaccount:default:build-controller' | |
puts ' Creating key and certificate for router...' | |
session.exec! 'CA=/openshift.local.config/master; oadm ca create-server-cert --signer-cert=$CA/ca.crt --signer-key=$CA/ca.key --signer-serial=$CA/ca.serial.txt --hostnames="*.cloudapps.example.com" --cert=$CA/cloudapps.crt --key=$CA/cloudapps.key; cat $CA/cloudapps.crt $CA/cloudapps.key $CA/ca.crt > $CA/cloudapps.router.pem' | |
puts ' Starting router...' | |
session.exec! 'oadm router --replicas=1 --default-cert=/openshift.local.config/master/cloudapps.router.pem --credentials=/openshift.local.config/master/openshift-router.kubeconfig --service-account=router' | |
puts ' Adding "alice" and "joe" users...' | |
session.exec! 'useradd alice; useradd joe' | |
puts ' Fixing KUBECONFIG setting in /etc/profile.d/openshift.sh...' | |
session.exec! 'sed -i -e \'/KUBECONFIG=/ s/^/[[ $EUID -eq 0 ]] \\&\\& /\' /etc/profile.d/openshift.sh' | |
puts ' Logging alice and joe in...' | |
session.exec! 'su - alice -c \'oc login -u alice -p alice --certificate-authority=/openshift.local.config/master/ca.crt --server=https://localhost:8443/\'' | |
session.exec! 'su - joe -c \'oc login -u joe -p joe --certificate-authority=/openshift.local.config/master/ca.crt --server=https://localhost:8443/\'' | |
puts ' Creating aliceproject and joeproject projects...' | |
session.exec! 'su - alice -c \'oc new-project aliceproject\'' | |
session.exec! 'su - joe -c \'oc new-project joeproject\'' | |
puts ' Adding aliceproject and joeproject builder service accounts to privileged SCC...' | |
session.exec! 'oc patch scc/privileged --patch=\'[{"op":"add","path":"/users/-","value":"system:serviceaccount:aliceproject:builder"},{"op":"add","path":"/users/-","value":"system:serviceaccount:joeproject:builder"}]\' --type=json' | |
end | |
rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT => e | |
if (retries+=1) < 12 | |
$stderr.puts "Error connecting to #{instance.public_dns_name}: #{e.message}. Retrying..." | |
sleep 5 | |
retry | |
end | |
$stderr.puts "Unable to connect to #{instance.public_dns_name}." | |
end | |
end | |
parse_args | |
case $COMMAND | |
when 'list' | |
instances = find_instance $INSTANCE | |
instances.each do |instance| | |
puts 'Found ' + instance.tags.find{|t| t.key == 'Name'}.value, | |
instance.tags.inspect, '' | |
end | |
when 'launch' | |
instances = launch_instance $INSTANCE | |
instances.each {|instance| configure_instance instance} | |
when 'configure' | |
instances = find_instance $INSTANCE | |
instances.each {|instance| configure_instance instance} | |
when 'terminate' | |
instances = find_instance $INSTANCE | |
instances.each do |instance| | |
puts "Terminating instance #{instance.public_dns_name} (#{instance.id})..." | |
instance.terminate | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment