bbc-cosmos-tools 0.5.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d1b3b62925024f13d3a5b7faae3e72eefa93f6dc
4
- data.tar.gz: ffdad2cc037fcf0f7a80e0621a5e112866caf6bc
3
+ metadata.gz: 682aa789050e6b06223d07a9da105df6abdc966d
4
+ data.tar.gz: 2256eaa0c3a4c060fb26fdaa8fa637796602723c
5
5
  SHA512:
6
- metadata.gz: 70676ba07d90b32de1b3d0e780f5bc505728c9e2668719b55e9aed3a61298b3f65077a907ff46ba8eb4c72003be0bb58671a836cf5439728e823fc60473f9b2f
7
- data.tar.gz: cbb8ec4259306edc4f0269acca9b06173ccfb0c16d310057d19e9c512baf26c7729bbab071d2026fb4b0712c3e681fb7c35654861bed976eee37fa90c9728291
6
+ metadata.gz: 8cb7f2f87c0d45e710caa0fd6f85b887410927bd37570894cfbee4eb88d7bd8df4c2976a14bd2a5e05bb505b52e95a950ec5ea7192b55e9fdf81c22643264188
7
+ data.tar.gz: 9b4b400d1c6cd2da4bb81c22518dfb5ee8e80217a9b7f3879bbec47cd50edbce62bf9a0478c87131e4f60b37b9318b68150f1170d101565815b45a78ffa021cc
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in bbc-cosmos-config.gemspec
4
4
  gemspec
@@ -8,12 +8,12 @@ Gem::Specification.new do |spec|
8
8
  spec.version = BBC::Cosmos::Tools::VERSION
9
9
  spec.authors = ["Steven Jack"]
10
10
  spec.email = ["stevenmajack@gmail.com"]
11
- spec.description = %q{Tool for interacting with BBC Cosmos platform}
12
- spec.summary = %q{Tool for pusing config to cosmos and controlling cloudformation templates}
11
+ spec.description = "Tool for interacting with BBC Cosmos platform"
12
+ spec.summary = "Tool for pusing config to cosmos and controlling cloudformation templates"
13
13
  spec.homepage = ""
14
14
  spec.license = "MIT"
15
15
 
16
- spec.files = `git ls-files`.split($/)
16
+ spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
17
17
  spec.executables << "bbc-cosmos-tools"
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
@@ -24,5 +24,6 @@ Gem::Specification.new do |spec|
24
24
  spec.add_runtime_dependency "thor"
25
25
  spec.add_runtime_dependency "faraday"
26
26
  spec.add_runtime_dependency "cfndsl"
27
- spec.add_runtime_dependency "aws-sdk", "~> 1"
27
+ spec.add_runtime_dependency "aws-sdk", "~> 1.63.0"
28
+ spec.add_runtime_dependency "highline"
28
29
  end
data/bin/bbc-cosmos-tools CHANGED
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'pathname'
3
+ require "pathname"
4
4
 
5
5
  root = Pathname.new(__FILE__).dirname.parent
6
- lib_path = (root + 'lib').realdirpath
6
+ lib_path = (root + "lib").realdirpath
7
7
 
8
8
  $LOAD_PATH.unshift(lib_path)
9
9
 
10
- require 'bbc/cosmos/tools/app'
10
+ require "bbc/cosmos/tools/app"
11
11
 
12
12
  include BBC::Cosmos::Tools
13
13
 
@@ -1,18 +1,17 @@
1
- require 'pathname'
2
- require 'faraday'
3
- require 'openssl'
1
+ require "pathname"
2
+ require "faraday"
3
+ require "openssl"
4
4
 
5
5
  module BBC
6
6
  module Cosmos
7
7
  module Tools
8
8
  class API
9
-
10
9
  def initialize(host, key_path)
11
10
  @connection = Faraday.new host, :ssl => {
12
11
  :client_key => client_key(key_path),
13
12
  :client_cert => client_cert(key_path),
14
13
  :verify => false,
15
- :version => 'TLSv1'
14
+ :version => "TLSv1"
16
15
  }
17
16
  end
18
17
 
@@ -28,12 +27,12 @@ module BBC
28
27
  @connection.get path
29
28
  end
30
29
 
31
- def put(path, payload, content_type = 'application/json')
30
+ def put(path, payload, content_type = "application/json")
32
31
  content_type_from content_type
33
32
  @connection.put path, payload
34
33
  end
35
34
 
36
- def post(path, payload, content_type = 'application/json')
35
+ def post(path, payload, content_type = "application/json")
37
36
  content_type_from content_type
38
37
  @connection.post path, payload
39
38
  end
@@ -41,7 +40,6 @@ module BBC
41
40
  def content_type_from(type)
42
41
  @connection.headers[:content_type] = type
43
42
  end
44
-
45
43
  end
46
44
  end
47
45
  end
@@ -1,8 +1,8 @@
1
1
  require "thor"
2
- require 'bbc/cosmos/tools/commands/config'
3
- require 'bbc/cosmos/tools/commands/release'
4
- require 'bbc/cosmos/tools/commands/stack'
5
- require 'bbc/cosmos/tools/commands/component'
2
+ require "bbc/cosmos/tools/commands/config"
3
+ require "bbc/cosmos/tools/commands/release"
4
+ require "bbc/cosmos/tools/commands/stack"
5
+ require "bbc/cosmos/tools/commands/component"
6
6
 
7
7
  module BBC
8
8
  module Cosmos
@@ -1,20 +1,19 @@
1
- require 'cfndsl'
2
- require 'json'
1
+ require "cfndsl"
2
+ require "json"
3
3
 
4
4
  module BBC
5
5
  module Cosmos
6
6
  module Tools
7
7
  module Cloudformation
8
8
  class Generator
9
-
10
- RESERVED_MAIN_STACK_PARAMS = ['Environment', 'PublicSubnet1Id', 'PublicSubnet2Id', 'PublicSubnet3Id', 'ImageId', 'VpcId', 'PrivateSubnet1Id', 'PrivateSubnet2Id', 'PrivateSubnet3Id', 'BastionAccessSecurityGroup', 'DomainNameBase', 'KeyName', 'S3BucketArn']
9
+ RESERVED_MAIN_STACK_PARAMS = %w(Environment PublicSubnet1Id PublicSubnet2Id PublicSubnet3Id ImageId VpcId PrivateSubnet1Id PrivateSubnet2Id PrivateSubnet3Id BastionAccessSecurityGroup DomainNameBase KeyName S3BucketArn)
11
10
 
12
11
  def self.component_exists?(component, config)
13
- config.resources['cloudformation']['components'][component]
12
+ config.resources["cloudformation"]["components"][component]
14
13
  end
15
14
 
16
15
  def self.stack_exists?(component, config, stack)
17
- config.resources['cloudformation']['components'][component][stack]
16
+ config.resources["cloudformation"]["components"][component][stack]
18
17
  end
19
18
 
20
19
  def self.create(component, config, options, to_json = false, &block)
@@ -22,28 +21,28 @@ module BBC
22
21
  template.declare(&block)
23
22
 
24
23
  if template.checkRefs || CfnDsl::Errors.errors?
25
- self.raise_error template
24
+ raise_error template
26
25
  else
27
26
  hash = JSON.parse(template.to_json)
28
- hash['Parameters'] ||= {}
27
+ hash["Parameters"] ||= {}
29
28
 
30
29
  if component_exists?(component, config) && stack_exists?(component, config, options[:stack])
31
30
  component_parameters(config.resources, options, component).each do |key, value|
32
- hash['Parameters'][key]['Default'] = value if hash['Parameters'][key]
31
+ hash["Parameters"][key]["Default"] = value if hash["Parameters"][key]
33
32
  end
34
33
  end
35
34
 
36
- hash.delete_if { |k, v| k == 'Parameters' && v == {} }
35
+ hash.delete_if { |k, v| k == "Parameters" && v == {} }
37
36
 
38
37
  to_json ? JSON.pretty_generate(hash) : hash
39
38
  end
40
39
  end
41
40
 
42
41
  def self.parameters(data, main_stack = true)
43
- if data['Parameters']
44
- data['Parameters'].reduce({}) do |object, (key, value)|
42
+ if data["Parameters"]
43
+ data["Parameters"].reduce({}) do |object, (key, value)|
45
44
  object.tap do |o|
46
- o[key] = value['Default'] unless reserved_main_stack_param_for(key, main_stack) && value['Default'].nil?
45
+ o[key] = value["Default"] unless reserved_main_stack_param_for(key, main_stack) && value["Default"].nil?
47
46
  end
48
47
  end
49
48
  else
@@ -53,27 +52,27 @@ module BBC
53
52
 
54
53
  def self.raise_error(template)
55
54
  if CfnDsl::Errors.errors?
56
- raise("Errors in template: #{CfnDsl::Errors.errors.join(' # ')}")
57
- elsif (invalid_references = template.checkRefs())
58
- raise("Invalid Refs: #{invalid_references.join(' # ')}")
55
+ fail("Errors in template: #{CfnDsl::Errors.errors.join(' # ')}")
56
+ elsif (invalid_references = template.checkRefs)
57
+ fail("Invalid Refs: #{invalid_references.join(' # ')}")
59
58
  end
60
59
  end
61
60
 
62
61
  private
63
62
 
64
63
  def self.component_stack_details(resources, options, component)
65
- raise("cloudformation: -> components: node is missing from the environment resource file") unless resources.has_key?("cloudformation") && resources['cloudformation'].has_key?("components")
64
+ fail("cloudformation: -> components: node is missing from the environment resource file") unless resources.key?("cloudformation") && resources["cloudformation"].key?("components")
66
65
 
67
- components = resources['cloudformation']['components']
68
- raise("'#{component}' node missing from cloudformation: -> components: nodes") unless components.has_key?(component)
66
+ components = resources["cloudformation"]["components"]
67
+ fail("'#{component}' node missing from cloudformation: -> components: nodes") unless components.key?(component)
69
68
  component = components[component]
70
69
 
71
- raise("'#{options[:stack]}' stack node missing from cloudformation: -> components: -> #{component}:") unless component.has_key?(options[:stack])
70
+ fail("'#{options[:stack]}' stack node missing from cloudformation: -> components: -> #{component}:") unless component.key?(options[:stack])
72
71
  component[options[:stack]]
73
72
  end
74
73
 
75
74
  def self.variants(component_meta, variant = nil)
76
- component_meta.has_key?('variants') ? component_meta['variants'][variant] : component_meta.fetch('parameters', {})
75
+ component_meta.key?("variants") ? component_meta["variants"][variant] : component_meta.fetch("parameters", {})
77
76
  end
78
77
 
79
78
  def self.component_parameters(resources, options, component)
@@ -84,10 +83,8 @@ module BBC
84
83
  def self.reserved_main_stack_param_for(key, main_stack)
85
84
  main_stack && RESERVED_MAIN_STACK_PARAMS.include?(key)
86
85
  end
87
-
88
86
  end
89
87
  end
90
88
  end
91
89
  end
92
90
  end
93
-
@@ -1,6 +1,6 @@
1
1
  require "thor"
2
2
  require "pathname"
3
- require 'json'
3
+ require "json"
4
4
  require "bbc/cosmos/tools/config"
5
5
 
6
6
  module BBC
@@ -14,10 +14,10 @@ module BBC
14
14
 
15
15
  package_name "BBC Cosmos config tool"
16
16
 
17
- class_option :key_path, :type => :string, :default => ENV['BBC_COSMOS_TOOLS_CERT'], :desc => "The path to your dev cert, by default the value of the env variable $BBC_COSMOS_TOOLS_CERT is used"
18
- class_option :env, :type => :string, :default => 'int', :desc => "The environment to target"
17
+ class_option :key_path, :type => :string, :default => ENV["BBC_COSMOS_TOOLS_CERT"], :desc => "The path to your dev cert, by default the value of the env variable $BBC_COSMOS_TOOLS_CERT is used"
18
+ class_option :env, :type => :string, :default => "int", :desc => "The environment to target"
19
19
  class_option :base, :type => :string, :desc => "The base path for the configs repo"
20
- class_option :project, :type => :string, :default => ENV['BBC_COSMOS_TOOLS_PROJECT'], :desc => "The name of the project, by default the value of the env variable $BBC_COSMOS_TOOLS_PROJECT is used"
20
+ class_option :project, :type => :string, :default => ENV["BBC_COSMOS_TOOLS_PROJECT"], :desc => "The name of the project, by default the value of the env variable $BBC_COSMOS_TOOLS_PROJECT is used"
21
21
 
22
22
  def initialize(args = [], local_options = {}, config = {})
23
23
  super(args, local_options, config)
@@ -33,7 +33,7 @@ module BBC
33
33
  def banner(component = nil)
34
34
  output = component.nil? ? "\n" : "\n#{get_key_value('Component', component)}\n"
35
35
  options.reduce(output) do |string, (key, value)|
36
- string += "#{get_key_value(key.capitalize.gsub(/_/, " "), value)}\n"
36
+ string += "#{get_key_value(key.capitalize.gsub(/_/, ' '), value)}\n"
37
37
  end
38
38
  end
39
39
 
@@ -42,7 +42,7 @@ module BBC
42
42
  end
43
43
 
44
44
  def api_error(response, die = true)
45
- error_message = JSON.parse(response.body)['message']
45
+ error_message = JSON.parse(response.body)["message"]
46
46
  error(error_message, die)
47
47
  end
48
48
 
@@ -66,18 +66,16 @@ module BBC
66
66
  private
67
67
 
68
68
  def setup_config
69
- config_base = !options[:base].nil? && File.directory?(options[:base]) ? Pathname.new(options[:base]) : Pathname.pwd.join('.')
70
- raise("Config directory: #{config_base} doesn't exist") unless File.directory?(config_base)
69
+ config_base = !options[:base].nil? && File.directory?(options[:base]) ? Pathname.new(options[:base]) : Pathname.pwd.join(".")
70
+ fail("Config directory: #{config_base} doesn't exist") unless File.directory?(config_base)
71
71
  @config = BBC::Cosmos::Tools::Config.new(
72
72
  config_base,
73
73
  options[:project],
74
74
  options[:env]
75
75
  )
76
76
  end
77
-
78
77
  end
79
78
  end
80
79
  end
81
80
  end
82
81
  end
83
-
@@ -1,13 +1,13 @@
1
1
  require "bbc/cosmos/tools/api"
2
2
  require "aws-sdk"
3
3
  require "json"
4
+ require "highline/import"
4
5
 
5
6
  module BBC
6
7
  module Cosmos
7
8
  module Tools
8
9
  module Commands
9
10
  class Component < Base
10
-
11
11
  desc "instances <COMPONENT>", "Show instances of the given component"
12
12
  method_option :show_tag, :type => :string, :desc => "Show tag"
13
13
  def instances(component)
@@ -18,46 +18,106 @@ module BBC
18
18
  tag = options[:show_tag]
19
19
 
20
20
  rows = instance_ids(component).map do |id|
21
- [id].tap { |row|
22
- row << ec2.instances[id].tags[tag] if tag
23
- }
21
+ [id].tap do |row|
22
+ row << ec2.instances[id].tags[tag] if tag
23
+ end
24
24
  end
25
25
 
26
- headers = ['Instance ID']
26
+ headers = ["Instance ID"]
27
27
  headers << tag if tag
28
28
 
29
29
  print_table build_table(headers, rows)
30
30
  end
31
31
 
32
+ desc "SSH <COMPONENT>", "Gain SSH"
33
+ def ssh(component)
34
+ meta = make_request("env/#{options[:env]}/component/#{component}/instances")
35
+
36
+ meta.count == 1 ? single_instance(component, meta)
37
+ : multiple_instance(component, meta)
38
+ end
39
+
32
40
  private
41
+
42
+ def api
43
+ @api ||= BBC::Cosmos::Tools::API.new(
44
+ "https://api.live.bbc.co.uk", options[:key_path]
45
+ )
46
+ end
47
+
48
+ def single_instance(component, meta)
49
+ session(component, meta[0]["id"], meta[0]["private_ip_address"])
50
+ end
51
+
52
+ def multiple_instance(component, meta)
53
+ instance_id = select_instance(meta)
54
+ session(component, instance_id, extract_ipaddress(meta, instance_id))
55
+ end
56
+
57
+ def session(component, instance_id, ip_address)
58
+ post_data(component, instance_id)
59
+ output_message(component, ip_address, instance_id)
60
+ end
61
+
62
+ def select_instance(meta)
63
+ choose do |menu|
64
+ say "Multiple instances detected, please select one", :green
65
+
66
+ meta.map do |i|
67
+ menu.choice(i["id"].to_sym)
68
+ end
69
+ end.to_s
70
+ end
71
+
72
+ def extract_ipaddress(meta, instance)
73
+ meta.detect { |hash| hash.value?(instance) }.fetch("private_ip_address")
74
+ end
75
+
76
+ def output_message(component, ip, id)
77
+ say "SSH setup for #{component} on #{options[:env]}, your IP for #{id} is #{ip}", :green
78
+ end
79
+
80
+ def post_data(component, id)
81
+ post_data = { "instance_id" => id }
82
+
83
+ endpoint = "/cosmos/env/#{options[:env]}/component/#{component}/logins/create"
84
+ api.post(endpoint, post_data.to_json).tap do |response|
85
+ fail Exception, response.body if response.status != 201
86
+ end
87
+ end
88
+
89
+ def make_request(path)
90
+ JSON.parse(api.get("/cosmos/#{path}").tap do |request|
91
+ fail Exception, request.body if request.status != 200
92
+ end.body)
93
+ end
94
+
33
95
  def instance_ids(component)
34
96
  response = BBC::Cosmos::Tools::API.new(
35
- config.app['api'],
97
+ config.app["api"],
36
98
  options[:key_path]
37
- )
38
- .get "/cosmos/env/#{options[:env]}/component/#{component}/instances"
99
+ ).get "/cosmos/env/#{options[:env]}/component/#{component}/instances"
39
100
 
40
- raise Exception, response.body if response.status != 200
101
+ fail Exception, response.body if response.status != 200
41
102
 
42
- JSON.parse(response.body).map { |instance|
103
+ JSON.parse(response.body).map do |instance|
43
104
  instance.fetch "id"
44
- }
105
+ end
45
106
  end
46
107
 
47
108
  def aws_credentials
48
- response = BBC::Cosmos::Tools::API.new(
49
- "https://wormhole.cloud.bbc.co.uk",
50
- options[:key_path]
51
- )
52
- .get "/login/credentials"
109
+ response = BBC::Cosmos::Tools::API.new(
110
+ "https://wormhole.cloud.bbc.co.uk",
111
+ options[:key_path]
112
+ ).get "/login/credentials"
53
113
 
54
- raise Exception, response.body if response.status != 200
114
+ fail Exception, response.body if response.status != 200
55
115
 
56
116
  credentials = JSON.parse response.body
57
117
 
58
118
  { :access_key_id => credentials["accessKeyId"],
59
- :secret_access_key => credentials['secretAccessKey'],
60
- :session_token => credentials['sessionToken'],
119
+ :secret_access_key => credentials["secretAccessKey"],
120
+ :session_token => credentials["sessionToken"],
61
121
  :region => "eu-west-1" }
62
122
  end
63
123
  end
@@ -1,8 +1,8 @@
1
- require 'json'
2
- require 'pathname'
3
- require 'bbc/cosmos/tools/commands/base'
4
- require 'bbc/cosmos/tools/cosmos_configuration'
5
- require 'bbc/cosmos/tools/api'
1
+ require "json"
2
+ require "pathname"
3
+ require "bbc/cosmos/tools/commands/base"
4
+ require "bbc/cosmos/tools/cosmos_configuration"
5
+ require "bbc/cosmos/tools/api"
6
6
 
7
7
  module BBC
8
8
  module Cosmos
@@ -22,12 +22,11 @@ module BBC
22
22
  method_option :cosmos_format, :type => :boolean, :desc => "Toogles if the output should be in the cosmos format"
23
23
  def generate(component)
24
24
  if options[:write]
25
- File.open("#{component}.json", 'w') do |f|
25
+ File.open("#{component}.json", "w") do |f|
26
26
  f.write(JSON.pretty_generate(cosmos_config.component(component)))
27
27
  end
28
28
  end
29
29
 
30
-
31
30
  if options[:output] == "machine"
32
31
  say JSON.pretty_generate(cosmos_config.cosmos_component(component)), :white
33
32
 
@@ -46,7 +45,6 @@ module BBC
46
45
  rescue Exception => e
47
46
  error e.message
48
47
  end
49
-
50
48
  end
51
49
 
52
50
  desc "config list", "Lists all components for a given project"
@@ -71,48 +69,41 @@ module BBC
71
69
  rescue Exception => e
72
70
  error e.message
73
71
  end
74
-
75
72
  end
76
73
 
77
74
  desc "config push [COMPONENT_ID = nil]", "Push config for a component to the cosmos API"
78
75
  method_option :force, :type => :boolean, :desc => "This skips asking of you want to push the changes"
79
76
  def push(component_id = nil)
80
- begin
77
+ components = component_id.nil? ? cosmos_config.component_keys : [component_id]
78
+ say "#{banner}\n"
81
79
 
82
- components = component_id.nil? ? cosmos_config.component_keys : [component_id]
83
- say "#{banner}\n"
80
+ reply = yes?("Are you sure you want to push changes for #{components.length} components(s) to #{options[:env]}?", :yellow) unless options[:force]
81
+ if reply || reply.nil?
84
82
 
85
- reply = yes?("Are you sure you want to push changes for #{components.length} components(s) to #{options[:env]}?", :yellow) unless options[:force]
86
- if reply || reply.nil?
83
+ components.each do |id|
84
+ say "\n#{get_key_value('Component', id)}\n"
87
85
 
88
- components.each do |id|
86
+ component_config = JSON.generate(cosmos_config.cosmos_component id)
89
87
 
90
- say "\n#{get_key_value('Component', id)}\n"
88
+ @api = BBC::Cosmos::Tools::API.new(config.app["api"], options[:key_path])
89
+ response = @api.put sprintf(config.app["config_endpoint"], options[:env], id), component_config
91
90
 
92
- component_config = JSON.generate(cosmos_config.cosmos_component id)
93
-
94
- @api = BBC::Cosmos::Tools::API.new(config.app['api'], options[:key_path])
95
- response = @api.put sprintf(config.app['config_endpoint'], options[:env], id), component_config
96
-
97
- if response.success?
98
- say 'Successfully saved', :green
99
- else
100
- api_error response
101
- end
91
+ if response.success?
92
+ say "Successfully saved", :green
93
+ else
94
+ api_error response
102
95
  end
103
-
104
- else
105
- error 'Action cancelled'
106
96
  end
107
97
 
108
- rescue Exception => e
109
- error e.message
98
+ else
99
+ error "Action cancelled"
110
100
  end
111
- end
112
101
 
102
+ rescue Exception => e
103
+ error e.message
104
+ end
113
105
  end
114
106
  end
115
107
  end
116
108
  end
117
109
  end
118
-