ecs-kingpin 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2077aa518e8ab8b6bf3d6cc7eda665944f220e02
4
+ data.tar.gz: 0262ffb5562024ad8e1dec80dd5caba407ac6a6f
5
+ SHA512:
6
+ metadata.gz: b2dd4f86e5ece59903b30c6bad4033badbc6edcf60dd5d84b42e1e88bbda717d240b3bbf8f1c8ce5c17362ed503bad62f6c8902dd5cedf43c7f30247ec2620d7
7
+ data.tar.gz: 251ef01a846eb465ce27aa2e0888d89a1ec59fe9505044ebb8b26f1dcd841293d6db767d16f20a3da3e211f7e675064861d17b82e2bcf426fdcf9e73ed5ec27c
data/.gitignore ADDED
@@ -0,0 +1,58 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ # .env
15
+
16
+ ## Specific to RubyMotion:
17
+ .dat*
18
+ .repl_history
19
+ build/
20
+ *.bridgesupport
21
+ build-iPhoneOS/
22
+ build-iPhoneSimulator/
23
+
24
+ ## Specific to RubyMotion (use of CocoaPods):
25
+ #
26
+ # We recommend against adding the Pods directory to your .gitignore. However
27
+ # you should judge for yourself, the pros and cons are mentioned at:
28
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
29
+ #
30
+ # vendor/Pods/
31
+
32
+ ## Documentation cache and generated files:
33
+ /.yardoc/
34
+ /_yardoc/
35
+ /doc/
36
+ /rdoc/
37
+
38
+ ## Environment normalization:
39
+ /.bundle/
40
+ /vendor/bundle
41
+ /lib/bundler/man/
42
+
43
+ # for a library or gem, you might want to ignore these files since the code is
44
+ # intended to run in multiple environments; otherwise, check them in:
45
+ # Gemfile.lock
46
+ # .ruby-version
47
+ # .ruby-gemset
48
+
49
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
50
+ .rvmrc
51
+
52
+ # Specific
53
+ *.yml
54
+ *.yaml
55
+ task-definition.json
56
+ *.tfvars
57
+ log/
58
+ .terraform*
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+ gem 'aws-sdk', '2.6.2'
3
+ gem 'trollop', '2.1.2'
4
+ gem 'rake'
5
+ gem 'hashie', '3.4.6'
data/Gemfile.lock ADDED
@@ -0,0 +1,23 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ aws-sdk (2.6.2)
5
+ aws-sdk-resources (= 2.6.2)
6
+ aws-sdk-core (2.6.2)
7
+ jmespath (~> 1.0)
8
+ aws-sdk-resources (2.6.2)
9
+ aws-sdk-core (= 2.6.2)
10
+ jmespath (1.3.1)
11
+ rake (10.4.2)
12
+ trollop (2.1.2)
13
+
14
+ PLATFORMS
15
+ ruby
16
+
17
+ DEPENDENCIES
18
+ aws-sdk (= 2.6.2)
19
+ rake
20
+ trollop (= 2.1.2)
21
+
22
+ BUNDLED WITH
23
+ 1.13.6
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2016 Jens Skott
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # ecs-kingpin
2
+ Quick rubyscript to test ecs api and create and update tasks and services
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
data/bin/kingpin ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require_relative '../lib/kingpin.rb'
4
+
5
+ Kingpin.new
data/def.yml ADDED
@@ -0,0 +1,83 @@
1
+ # Type of a service to maintain: PublicService creates public ELB, PrivateService creates internal ELB
2
+ type: PublicService
3
+ version: 1
4
+
5
+ metadata:
6
+ name: my-frontend-ui
7
+ labels:
8
+ - name: "datadog"
9
+ value: "true"
10
+ - name: "ecs"
11
+ value: "false"
12
+ spec:
13
+
14
+ # Container autoscaling
15
+ scaling:
16
+ min: 1
17
+ desired: 1
18
+ max: 2
19
+
20
+ # Roles required
21
+ iamRoles:
22
+ - "ecsBasicRole" # Always added
23
+ - "s3ReadAccess"
24
+ - "ec2Defaults"
25
+
26
+ # Shared volumes on ECS cluster
27
+ volumes:
28
+ - name: "webdata"
29
+ source: "/ecs/webdata"
30
+
31
+ # Container definition
32
+ containers:
33
+ # Container for Nginx
34
+ - name: nginx
35
+ image: ~/nginx:1.7.9 # If image starts with "~/" - auto-detect service-specific registry URL
36
+ essential: true # main container - if down, then restart all
37
+
38
+ env:
39
+ - name: "SERVER_PORT"
40
+ value: 8080
41
+
42
+ ports:
43
+ - containerPort: 8080 # Port EXPOSE
44
+ port: 80 # ELB & ELB Target Group port (listener)
45
+ protocol: "http" # http or https
46
+ name: "public" # "_default_" if omited (may only be one unnamed port)
47
+
48
+ # Secondary ports are currently not supported. But if they were...
49
+ # - containerPort: 8081 # Port EXPOSE
50
+ # port: 81
51
+ # protocol: "https"
52
+ # name: "management"
53
+ logs:
54
+ logdriver: "gelf"
55
+ options:
56
+ gelf-address: "udp://crap.com:5212"
57
+ labels: "hej, då"
58
+
59
+ health:
60
+ portName: "public" # defaults to "_default_"
61
+ path: "/health"
62
+ timeout: 10s
63
+ interval: 5s
64
+ healthyTh: 3
65
+ unhealthyTh: 2
66
+
67
+ volumes: # Volume mounting
68
+ - sourceVolume:
69
+ containerPath:
70
+
71
+ resources: # Resource limits
72
+ cpu: ""
73
+ memory: ""
74
+
75
+ links: #Container links
76
+ - "redis:redis"
77
+
78
+ # Container for Redis
79
+ - name: redis
80
+ image: redis
81
+ essential: false
82
+ resources:
83
+ memory: 128M # Units are parsed to be user friendly, no unit = MB
@@ -0,0 +1,21 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require 'bundler'
6
+ require 'rake'
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = "ecs-kingpin"
10
+ spec.authors = ["jens.skott"]
11
+ spec.email = ["jens.skott@gmail.com"]
12
+ spec.summary = %q{Create and manage ecs resources}
13
+ spec.description = %q{Manage ecs trough aws api with commandline flags}
14
+ spec.homepage = "http://github.com/jensskott/kingpin"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files`.split($\)
18
+ spec.executables = ["kingpin"]
19
+ spec.require_paths = [lib]
20
+ spec.version = '0.1.2'
21
+ end
@@ -0,0 +1,21 @@
1
+ def connectEcs(region)
2
+ Aws::ECS::Client.new(region: region)
3
+ end
4
+
5
+ def awsBucket(region, bucketName)
6
+ # connect to s3
7
+ s3 = Aws::S3::Client.new(
8
+ region: region
9
+ )
10
+ buckets = s3.list_buckets.to_h
11
+ buckets.extend(Hashie::Extensions::DeepLocate)
12
+ bucket = buckets.deep_locate -> (key, value, _object) { key == :name && value.include?(bucketName) }
13
+ if bucket.empty?
14
+ Kinglog.log.info "Creating bucket #{bucketName}!"
15
+ s3.create_bucket(bucket: bucketName)
16
+ Kinglog.log.info "Enabling bucket versioning!"
17
+ s3.put_bucket_versioning(bucket: bucketName, versioning_configuration: { mfa_delete: 'Disabled', status: 'Enabled' })
18
+ else
19
+ Kinglog.log.info "Bucket allready exists"
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ class Kinglog
2
+ def self.log
3
+ # Create logdir
4
+ logdir = Dir.pwd + '/log'
5
+ Dir.mkdir logdir unless Dir.exist?(logdir)
6
+ # Create log
7
+ if @logger.nil?
8
+ @logger = Logger.new STDOUT
9
+ # @logger = Logger.new "#{logdir}/kingpin.log"
10
+ @logger.level = Logger::DEBUG
11
+ @logger.datetime_format = '%Y-%m-%d %H:%M:%S '
12
+ end
13
+ @logger
14
+ end
15
+ end
@@ -0,0 +1,58 @@
1
+ def fileOpts(file)
2
+ yaml = YAML.load_file(file.to_s)
3
+ yaml
4
+ end
5
+
6
+ def cliOpts
7
+ opts = Trollop.options do
8
+ version 'Kingpin 0.1.0'
9
+ banner <<-EOS
10
+ Manage your ECS resources.
11
+
12
+ Usage:
13
+ kinpin [options]
14
+ where [options] are:
15
+ EOS
16
+
17
+ opt :region, 'Put your aws region here', type: :string
18
+ opt :env, 'Application Environment', type: :string
19
+ opt :product, 'The product where your services are related', type: :string
20
+ opt :command, 'Use aws cli or terraform to create service', type: :string, default: 'aws'
21
+ opt :file, 'Yaml file to read data from', type: :string
22
+ opt :local, 'Use local config files', type: :bool, default: false
23
+ end
24
+
25
+ # Check for options needed
26
+ Trollop.die :region, 'Define a region' if opts[:region].nil?
27
+ Trollop.die :env, 'Define an environment' if opts[:env].nil?
28
+ Trollop.die :product, 'Define a product' if opts[:product].nil?
29
+ Trollop.die :file, 'Define a file' if opts[:file].nil?
30
+
31
+ # Merge filepath + filename to opts
32
+ opts[:file] = File.expand_path(opts[:file])
33
+
34
+ # Check if file exists
35
+ unless File.exist? (opts[:file])
36
+ Kinglog.log.error 'File does not exist'
37
+ abort
38
+ end
39
+
40
+ # Check valid extention
41
+ accepted_formats = ['.yml', '.yaml']
42
+ unless accepted_formats.include? File.extname(opts[:file])
43
+ Kinglog.log.error 'Not a valid yaml extention'
44
+ abort
45
+ end
46
+
47
+ # Check valid yaml
48
+ Kinglog.log.info "Validating yaml file : #{opts[:file]}"
49
+ if YAML.load_file(opts[:file]) == false
50
+ Kinglog.log.error "failed to read #{opts[:file]}: #{$ERROR_INFO}"
51
+ abort
52
+ end
53
+
54
+ # Puts all file options into opts[:yaml]
55
+ # Accessable trough opts[:yaml]['metadata'] ....
56
+ opts[:yaml] = fileOpts(opts[:file])
57
+ opts
58
+ end
@@ -0,0 +1,36 @@
1
+ def parseLabels(array)
2
+ hash = {}
3
+ array.each do |l|
4
+ key = l['name']
5
+ value = l['value']
6
+ hash[key] = value
7
+ end
8
+ hash
9
+ end
10
+
11
+ def parseContainers(array, labels)
12
+ arr = []
13
+ array.each do |l|
14
+ c = {}
15
+ c['name'] = l['name']
16
+ c['essential'] = l['essential']
17
+ c['image'] = l['image']
18
+ c['environment'] = l['env']
19
+ c['memory'] = l['resources']['memory']
20
+ c['cpu'] = l['resources']['cpu']
21
+ c['mountPoints'] = l['volumes']
22
+ c['docker_labels'] = labels
23
+ c['links'] = l['links']
24
+ c['logConfiguration'] = l['logs']
25
+ arr << c
26
+ end
27
+ arr
28
+ end
29
+
30
+ def parseService(array)
31
+ arr = []
32
+ array.each do |l|
33
+ arr << l['ports'] unless l['ports'].nil?
34
+ end
35
+ arr
36
+ end
@@ -0,0 +1,28 @@
1
+ # Create service.tfvars for terraform
2
+ def createServiceVars(array, ports)
3
+ product = array[:product]
4
+ service = array[:yaml]['metadata']['name']
5
+ env = array[:env]
6
+ region = array[:region]
7
+ port = ports[0][0]['containerPort']
8
+ containerPort = ports[0][0]['port']
9
+ type = array[:yaml]['type']
10
+ serviceVars = "product: <%= product %>
11
+ service: <%= service %>
12
+ env: <%= env %>
13
+ region: <%= region %>
14
+ elb_port: <%= port %>
15
+ container_port: <%= containerPort %>
16
+ <% if type == \"PublicService\" %>service_type: public<% else %>service_type: private<% end %>"
17
+
18
+ # Create a service.tfvars
19
+ renderer = ERB.new(serviceVars)
20
+ File.open('service.tfvars', 'w') do |f|
21
+ f.write renderer.result(binding)
22
+ end
23
+ Kinglog.log.info 'Wrote service.tfvars'
24
+ end
25
+
26
+ # Create service options for aws api
27
+ def serviceOpts
28
+ end
@@ -0,0 +1,23 @@
1
+ # Create task-definition for terraform
2
+ def createTaskDefinition(array, service)
3
+ json_opts = array.to_json
4
+ parsed = JSON.parse(json_opts)
5
+ last = parsed.last
6
+
7
+ task_definition = "{\"container_definitions\": [
8
+ <% parsed.each do |array| %><%= array.to_json %><% unless last[\"name\"] == array[\"name\"] %>,<% end %><% end %>
9
+ ],
10
+ \"family\": \"<%= service %>\"
11
+ }"
12
+
13
+ # Create a task-definition.json
14
+ renderer = ERB.new(task_definition)
15
+ File.open('task-definition.json', 'w') do |f|
16
+ f.write renderer.result(binding)
17
+ end
18
+ Kinglog.log.info 'Wrote task-defintion.json'
19
+ end
20
+
21
+ # Create task options for aws api
22
+ def taskOpts
23
+ end
@@ -0,0 +1,47 @@
1
+ # Check if terraform is installed on the system
2
+ def terrformExecCheck
3
+ `which terraform`
4
+ if $? == false
5
+ Kinglog.log.error 'Terrform executable not found, please install terraform'
6
+ abort
7
+ end
8
+ end
9
+
10
+ # Configure remote s3 bucket for terraform state file
11
+ def terrformConfig(array,bucketName)
12
+ product = array[:product]
13
+ service = array[:yaml]['metadata']['name']
14
+ env = array[:env]
15
+ region = array[:region]
16
+ serviceState = "#{service}-#{product}-#{env}.tfstate"
17
+ tfconfig = "terraform remote config -backend=s3 -backend-config=\"bucket=#{bucketName}\" \
18
+ -backend-config=\"key=#{serviceState}\" -backend-config=\"region=#{region}\""
19
+ system tfconfig
20
+ if $? != 0
21
+ Kinglog.log.error "Could not apply terraform config. Errorcode #{$?}"
22
+ abort
23
+ end
24
+ end
25
+
26
+ # Run terraform to apply config
27
+ def terraformRun
28
+ tf = "terraform apply"
29
+ tfget = "terraform get"
30
+ system tfget
31
+ system tf
32
+ if $? != 0
33
+ Kinglog.log.error "Can't run terraform config. Error: #{$?}"
34
+ abort
35
+ end
36
+ end
37
+
38
+ # Clean up all temporary files from terraform
39
+ def terraformCleanup
40
+ FileUtils.rm_rf('terraform.tfstate')
41
+ FileUtils.rm_rf('terraform.tfstate.backup')
42
+ FileUtils.rm_rf('mkmf.log')
43
+ FileUtils.rm_rf('.terraform')
44
+ FileUtils.rm_rf('task-definition.json')
45
+ FileUtils.rm_rf('service.tfvars')
46
+ Kinglog.log.info 'Removed all temporary files'
47
+ end
data/lib/kingpin.rb ADDED
@@ -0,0 +1,47 @@
1
+ # Require Gems
2
+ require 'aws-sdk'
3
+ require 'yaml'
4
+ require 'trollop'
5
+ require 'logger'
6
+ require 'json'
7
+ require 'erb'
8
+ require 'fileutils'
9
+ require 'mkmf'
10
+ require 'hashie'
11
+
12
+ # Require local libs
13
+ require_relative 'kingpin/aws'
14
+ require_relative 'kingpin/parse'
15
+ require_relative 'kingpin/options'
16
+ require_relative 'kingpin/log'
17
+ require_relative 'kingpin/terraform'
18
+ require_relative 'kingpin/service'
19
+ require_relative 'kingpin/task'
20
+
21
+ # Get options from CLI and file
22
+ class Kingpin
23
+ # Get options from cli
24
+ opts = cliOpts
25
+
26
+ # Define varaibles for service and tasks
27
+ labels = parseLabels(opts[:yaml]['metadata']['labels'])
28
+ servicePort = parseService(opts[:yaml]['spec']['containers'])
29
+ containers = parseContainers(opts[:yaml]['spec']['containers'], labels)
30
+
31
+ case opts[:command]
32
+ when 'aws'
33
+ puts 'use aws cli'
34
+ when 'terraform'
35
+ Kinglog.log.info 'Running terraform to configure ECS environment'
36
+ terrformExecCheck
37
+ createTaskDefinition(containers, opts[:yaml]['metadata']['name'])
38
+ createServiceVars(opts, servicePort)
39
+ if opts[:local] == false
40
+ bucketName = "terraformstate-ecs-#{opts[:product]}-#{opts[:env]}-#{opts[:region]}"
41
+ awsBucket(opts[:region], bucketName)
42
+ terrformConfig(opts,bucketName)
43
+ end
44
+ terraformRun
45
+ terraformCleanup if opts[:local] == false
46
+ end
47
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ecs-kingpin
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - jens.skott
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-11-08 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Manage ecs trough aws api with commandline flags
14
+ email:
15
+ - jens.skott@gmail.com
16
+ executables:
17
+ - kingpin
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - ".gitignore"
22
+ - Gemfile
23
+ - Gemfile.lock
24
+ - LICENSE
25
+ - README.md
26
+ - Rakefile
27
+ - bin/kingpin
28
+ - def.yml
29
+ - ecs-kingpin.gemspec
30
+ - lib/kingpin.rb
31
+ - lib/kingpin/aws.rb
32
+ - lib/kingpin/log.rb
33
+ - lib/kingpin/options.rb
34
+ - lib/kingpin/parse.rb
35
+ - lib/kingpin/service.rb
36
+ - lib/kingpin/task.rb
37
+ - lib/kingpin/terraform.rb
38
+ homepage: http://github.com/jensskott/kingpin
39
+ licenses:
40
+ - MIT
41
+ metadata: {}
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - "/home/jskott/dev/kingpin-ruby/lib"
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubyforge_project:
58
+ rubygems_version: 2.5.1
59
+ signing_key:
60
+ specification_version: 4
61
+ summary: Create and manage ecs resources
62
+ test_files: []