bbc-cosmos-tools 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +170 -0
- data/Rakefile +1 -0
- data/bbc-cosmos-tools.gemspec +27 -0
- data/bin/bbc-cosmos-tools +14 -0
- data/lib/bbc/cosmos/tools.rb +8 -0
- data/lib/bbc/cosmos/tools/api.rb +43 -0
- data/lib/bbc/cosmos/tools/app.rb +20 -0
- data/lib/bbc/cosmos/tools/cloudformation/generator.rb +50 -0
- data/lib/bbc/cosmos/tools/commands/base.rb +44 -0
- data/lib/bbc/cosmos/tools/commands/cloud_formation.rb +99 -0
- data/lib/bbc/cosmos/tools/commands/config.rb +112 -0
- data/lib/bbc/cosmos/tools/config.rb +61 -0
- data/lib/bbc/cosmos/tools/cosmos_configuration.rb +34 -0
- data/lib/bbc/cosmos/tools/version.rb +7 -0
- metadata +132 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3e38baa57a9e5441bbad593354a89d7f0f5a6cd1
|
4
|
+
data.tar.gz: 57864d5e0a145d157c91b6f96c120263607733dd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a7d5f1034b1787a801f5838deace842fbdcf7f2cb43c2bcc3970a6f19c8d27b14204e40cb1481d7f9612cd1dd62186bfea03c3e1b84a4dbcfaa1a868caf12620
|
7
|
+
data.tar.gz: 0b7958f49562ae2c76a673da212803a9e0e037b6a25778c1c64725476cf489c104d550b71181d0316889711c5b138f7ff6c014149b36ffcdffdbc9d7d3ef3b4f
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Steven Jack
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
# BBC::Cosmos::Tools
|
2
|
+
|
3
|
+
This gem provides tooling for interacting with cosmos. Currently it supports the following:
|
4
|
+
|
5
|
+
* Pushing component config to the cosmos API
|
6
|
+
* Creating stacks for a component in cosmos
|
7
|
+
* Updating stacks for a component in cosmos
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'bbc-cosmos-tools'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install bbc-cosmos-tools
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
The gem expects a certain folder structure for the config files:
|
26
|
+
|
27
|
+
#### Folder structure
|
28
|
+
|
29
|
+
```bash
|
30
|
+
├── configs
|
31
|
+
│ ├── {project name}.yaml.erb
|
32
|
+
│ ├── app.yam
|
33
|
+
├── resources
|
34
|
+
│ ├── {int/test/stage/live}
|
35
|
+
│ │ ├── {project-name}.yaml
|
36
|
+
├── stacks
|
37
|
+
│ ├── {component id/group_id}
|
38
|
+
│ │ ├── {stack name}
|
39
|
+
│ │ │ ├── aws {CFNDSL templates}
|
40
|
+
│ │ │ ├── template.rb
|
41
|
+
```
|
42
|
+
|
43
|
+
an example of this would be:
|
44
|
+
|
45
|
+
```bash
|
46
|
+
├── configs
|
47
|
+
│ ├── my_project.yaml.erb
|
48
|
+
│ ├── app.yam
|
49
|
+
├── resources
|
50
|
+
│ ├── int
|
51
|
+
│ │ ├── my_project.yaml
|
52
|
+
├── stacks
|
53
|
+
│ ├── my_wicked_component
|
54
|
+
│ │ ├── main
|
55
|
+
│ │ │ ├── aws
|
56
|
+
│ │ │ │ ├── auto_scaling
|
57
|
+
│ │ │ │ │ ├── group.rb
|
58
|
+
│ │ │ │ │ ├── launch_config.rb
|
59
|
+
│ │ │ ├── template.rb
|
60
|
+
```
|
61
|
+
|
62
|
+
#### Project resources structure
|
63
|
+
|
64
|
+
The project resources yaml file is used to describe the resources used within the project. The reason for having a single file is that you can define resources that are used in the cloudformation templates and config, so when for example an ARN changes this will be picked up across the CF templates and the config.
|
65
|
+
|
66
|
+
The file is spilt up into two section:
|
67
|
+
|
68
|
+
* The standard resource list, this is generally the ARNS for all the resources your component uses.
|
69
|
+
* Cloudformation parameters (These are usually referenced from the aforementioned)
|
70
|
+
|
71
|
+
Below is an annotated example of a resource config:
|
72
|
+
|
73
|
+
```yaml
|
74
|
+
|
75
|
+
sequencer:
|
76
|
+
name: 'example_name'
|
77
|
+
arn: 'example_arn'
|
78
|
+
|
79
|
+
roles:
|
80
|
+
broker:
|
81
|
+
name: &roles_broker_name 'some_iam_role_name'
|
82
|
+
|
83
|
+
cloudformation:
|
84
|
+
shared: &component_shared #<- This node is ignored, it's used as a base for other config templates
|
85
|
+
ACFParameter: 'Value'
|
86
|
+
AnotherCFParameter: 'Another value'
|
87
|
+
|
88
|
+
components:
|
89
|
+
'my-example-component': #<- The name of the component in cosmos
|
90
|
+
main: <- This is the name of the stack in cosmos
|
91
|
+
variants: <- This is so you can have a different variant of the same config, i.e for int/test one for durning the day and one for evening/weekends.
|
92
|
+
default: &my-example-component_default #<- We set this anchor so we can use this defaults in other variants
|
93
|
+
<<: *component_shared #<- We import the shared component params into these so we're not duplicating
|
94
|
+
ARoleParamForDefault: *roles_broker_name #<- We use the anchor for the roles set above to add them here, again stopping repitition
|
95
|
+
scheduled:
|
96
|
+
<<: *my-example-component_default
|
97
|
+
MinSize: 0
|
98
|
+
MaxSize: 0
|
99
|
+
|
100
|
+
```
|
101
|
+
|
102
|
+
#### Project Config structure
|
103
|
+
|
104
|
+
The project config is an ERB template that is renderer into a YAML file. it gets passed all resources from the resource config that can be used in the template. Below is an example of this:
|
105
|
+
|
106
|
+
```yaml
|
107
|
+
|
108
|
+
sequencer: &shared_sequencer
|
109
|
+
sequencer_table_name: '<%= config['sequencer']['name'] %>'
|
110
|
+
|
111
|
+
storage: &shared_storage
|
112
|
+
storage_path: '<%= config['storage']['name'] %>'
|
113
|
+
|
114
|
+
base: &shared
|
115
|
+
<<: *shared_sequencer
|
116
|
+
logger_path: 'some.loggingserver.com'
|
117
|
+
logger_port: '12201'
|
118
|
+
storage_path: '<% config['storage']['name]' %>
|
119
|
+
keep_all_messages: 'true'
|
120
|
+
|
121
|
+
components:
|
122
|
+
'test_component':
|
123
|
+
<<: *shared
|
124
|
+
some_specific_value: 'foo, bar'
|
125
|
+
```
|
126
|
+
|
127
|
+
The config has a number of components under a project, and the shared key allows you to
|
128
|
+
have shared config for the components. The config is built up from the shared data with
|
129
|
+
the component config merged in afterwards.
|
130
|
+
|
131
|
+
#### Application config
|
132
|
+
|
133
|
+
There's also an application config that stores data used by the app, at the moment this
|
134
|
+
is only the api endpoints.
|
135
|
+
|
136
|
+
```yaml
|
137
|
+
bbc:
|
138
|
+
cosmos:
|
139
|
+
api: "https://www.my.api.com"
|
140
|
+
create_endpoint: "/some/restful/endpoint"
|
141
|
+
update_endpoint: "/some/restful/endpoint"
|
142
|
+
```
|
143
|
+
|
144
|
+
The gem is a cli application, the commands are self documenting but below is a list of the commands for each set of sub commands
|
145
|
+
|
146
|
+
### Cosmos Config
|
147
|
+
|
148
|
+
```bash
|
149
|
+
bbc-cosmos-tools config generate
|
150
|
+
bbc-cosmos-tools config push
|
151
|
+
bbc-cosmos-tools config list
|
152
|
+
```
|
153
|
+
|
154
|
+
### Cloudformation
|
155
|
+
|
156
|
+
```bash
|
157
|
+
bbc-cosmos-tools cf generate
|
158
|
+
bbc-cosmos-tools cf create
|
159
|
+
bbc-cosmos-tools cf update
|
160
|
+
```
|
161
|
+
|
162
|
+
On each command you can use `--help` at the end to see the list of parameters and options that need to be passed into the command.
|
163
|
+
|
164
|
+
## Contributing
|
165
|
+
|
166
|
+
1. Fork it
|
167
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
168
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
169
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
170
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'bbc/cosmos/tools/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "bbc-cosmos-tools"
|
8
|
+
spec.version = BBC::Cosmos::Tools::VERSION
|
9
|
+
spec.authors = ["Steven Jack"]
|
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}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables << 'bbc-cosmos-tools'
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
|
24
|
+
spec.add_runtime_dependency 'thor'
|
25
|
+
spec.add_runtime_dependency 'faraday'
|
26
|
+
spec.add_runtime_dependency 'bbc-cfndsl'
|
27
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
root = Pathname.new(__FILE__).dirname.parent
|
6
|
+
lib_path = (root + 'lib').realdirpath
|
7
|
+
config_path = root + 'configs'
|
8
|
+
|
9
|
+
$LOAD_PATH.unshift(lib_path)
|
10
|
+
|
11
|
+
require 'bbc/cosmos/tools/app'
|
12
|
+
include BBC::Cosmos::Tools
|
13
|
+
|
14
|
+
App.start
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'faraday'
|
3
|
+
require 'openssl'
|
4
|
+
|
5
|
+
module BBC
|
6
|
+
module Cosmos
|
7
|
+
module Tools
|
8
|
+
class API
|
9
|
+
|
10
|
+
def initialize(host, key_path)
|
11
|
+
@connection = Faraday.new host, :ssl => {:client_key => client_key(key_path), :client_cert => client_cert(key_path), :verify => false }
|
12
|
+
end
|
13
|
+
|
14
|
+
def client_key(path)
|
15
|
+
OpenSSL::PKey::RSA.new(File.read path)
|
16
|
+
end
|
17
|
+
|
18
|
+
def client_cert(path)
|
19
|
+
OpenSSL::X509::Certificate.new(File.read path)
|
20
|
+
end
|
21
|
+
|
22
|
+
def get(path)
|
23
|
+
@connection.get path
|
24
|
+
end
|
25
|
+
|
26
|
+
def put(path, payload, content_type = 'application/json')
|
27
|
+
content_type_from content_type
|
28
|
+
@connection.put path, payload
|
29
|
+
end
|
30
|
+
|
31
|
+
def post(path, payload, content_type = 'application/json')
|
32
|
+
content_type_from content_type
|
33
|
+
@connection.post path, payload
|
34
|
+
end
|
35
|
+
|
36
|
+
def content_type_from(type)
|
37
|
+
@connection.headers[:content_type] = type
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "thor"
|
2
|
+
require_relative 'commands/config'
|
3
|
+
require_relative 'commands/cloud_formation'
|
4
|
+
|
5
|
+
module BBC
|
6
|
+
module Cosmos
|
7
|
+
module Tools
|
8
|
+
class App < Thor
|
9
|
+
include Thor::Actions
|
10
|
+
|
11
|
+
desc "config", "Cosmos sub commands"
|
12
|
+
subcommand "config", Commands::Config
|
13
|
+
|
14
|
+
desc "cf", "Cloudformation sub commands"
|
15
|
+
subcommand "cf", Commands::CloudFormation
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'bbc/cfndsl'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module BBC
|
5
|
+
module Cosmos
|
6
|
+
module Tools
|
7
|
+
module Cloudformation
|
8
|
+
class Generator
|
9
|
+
|
10
|
+
def self.create(component, config, options, to_json = false, &block)
|
11
|
+
|
12
|
+
template = CfnDsl::CloudFormationTemplate.new
|
13
|
+
template.declare(&block)
|
14
|
+
|
15
|
+
if template.checkRefs() || CfnDsl::Errors.errors?
|
16
|
+
self.raise_error template
|
17
|
+
else
|
18
|
+
hash = JSON.parse(template.to_json)
|
19
|
+
|
20
|
+
if config.resources['cloudformation']['components'][component][options[:stack]]
|
21
|
+
config.resources['cloudformation']['components'][component][options[:stack]]['variants'][options[:variant]].each do |key, value|
|
22
|
+
hash['Parameters'][key]['Default'] = value if hash['Parameters'][key]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
to_json ? JSON.pretty_generate(hash) : hash
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.parameters(data)
|
32
|
+
parameters = data['Parameters'].reduce({}) do |object, (key, value)|
|
33
|
+
object.tap { |o| o[key] = value['Default'] }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.raise_error(template)
|
38
|
+
if CfnDsl::Errors.errors?
|
39
|
+
raise("Errors in template: #{CfnDsl::Errors.errors.join(' # ')}")
|
40
|
+
elsif (invalid_references = template.checkRefs())
|
41
|
+
raise("Invalid Refs: #{invalid_references.join(' # ')}")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "pathname"
|
3
|
+
require 'json'
|
4
|
+
require "bbc/cosmos/tools/config"
|
5
|
+
|
6
|
+
module BBC
|
7
|
+
module Cosmos
|
8
|
+
module Tools
|
9
|
+
module Commands
|
10
|
+
class Base < Thor
|
11
|
+
attr_accessor :config
|
12
|
+
|
13
|
+
include Thor::Actions
|
14
|
+
|
15
|
+
package_name "BBC Cosmos config tool"
|
16
|
+
|
17
|
+
def initialize(args = [], local_options = {}, config = {})
|
18
|
+
super(args, local_options, config)
|
19
|
+
setup_config
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def setup_config
|
25
|
+
config_base = !options[:base].nil? && File.directory?(options[:base]) ? Pathname.new(options[:base]) : Pathname.pwd.join('.')
|
26
|
+
raise("Config directory: #{config_base} doesn't exist") unless File.directory?(config_base)
|
27
|
+
@config = BBC::Cosmos::Tools::Config.new(
|
28
|
+
config_base,
|
29
|
+
options[:project],
|
30
|
+
options[:env]
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def error(message)
|
35
|
+
say message, :red
|
36
|
+
exit 1
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require "bbc/cosmos/tools/config"
|
2
|
+
require 'bbc/cosmos/tools/commands/base'
|
3
|
+
require 'bbc/cosmos/tools/cloudformation/generator'
|
4
|
+
|
5
|
+
module BBC
|
6
|
+
module Cosmos
|
7
|
+
module Tools
|
8
|
+
module Commands
|
9
|
+
class CloudFormation < Base
|
10
|
+
|
11
|
+
desc "cf generate [COMPONENT]", "Generates a cloudformation template based on a type of component, the identifier and the environment"
|
12
|
+
method_option :env, :type => :string, :default => 'int', :desc => "The environment to target"
|
13
|
+
method_option :stack, :type => :string, :default => 'main', :desc => "The name of the stack to use"
|
14
|
+
method_option :variant, :type => :string, :default => 'default', :desc => "The variant to use, i.e default|scheduled|"
|
15
|
+
method_option :group, :type => :string, :default => nil, :desc => "The group name to override the component id"
|
16
|
+
method_option :project, :type => :string, :required => true, :desc => "The name of the project"
|
17
|
+
def generate(component)
|
18
|
+
|
19
|
+
component_identifier = options[:group].nil? ? component : options[:group]
|
20
|
+
say cloudformation(component_identifier, options), :green
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "cf create [COMPONENT, STACK_NAME = 'main', MAIN_STACK = false]", "Generates and create the cloudformation template for the specific component"
|
25
|
+
method_option :env, :type => :string, :default => 'int', :desc => "The environment to target"
|
26
|
+
method_option :stack, :type => :string, :default => 'main', :desc => "The name of the stack to use"
|
27
|
+
method_option :variant, :type => :string, :default => 'default', :desc => "The variant to use, i.e default|scheduled|"
|
28
|
+
method_option :group, :type => :string, :default => nil, :desc => "The group name to override the component id"
|
29
|
+
method_option :project, :type => :string, :required => true, :desc => "The name of the project"
|
30
|
+
|
31
|
+
method_option :key_path, :type => :string, :default => ENV['DEV_CERT_PATH'], :desc => "The path to your dev cert, by default it looks in the env variable '$DEV_CERT_PATH'"
|
32
|
+
def create(component, stack_name = 'main', main_stack = false)
|
33
|
+
|
34
|
+
component_identifier = options[:group].nil? ? component : options[:group]
|
35
|
+
data = cloudformation(component_identifier, options, false)
|
36
|
+
|
37
|
+
post_data = {
|
38
|
+
'name_suffix' => stack_name,
|
39
|
+
'service_stack' => main_stack,
|
40
|
+
'template' => data,
|
41
|
+
'parameters' => Tools::Cloudformation::Generator.parameters(data),
|
42
|
+
}
|
43
|
+
|
44
|
+
@api = BBC::Cosmos::Tools::Config::API.new(config.app['api'], options[:key_path])
|
45
|
+
response = @api.post sprintf(config.app['stack_create_endpoint'], options[:env], component), JSON.pretty_generate(post_data)
|
46
|
+
|
47
|
+
if response.success?
|
48
|
+
say "Stack creation for component '#{component}' successfully started", :green
|
49
|
+
else
|
50
|
+
say "There was an error creating your stack: #{response.body}", :red
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
desc "cf update [COMPONENT]", "Generates and updates the cloudformation template for the specific component"
|
56
|
+
method_option :env, :type => :string, :default => 'int', :desc => "The environment to target"
|
57
|
+
method_option :stack, :type => :string, :default => 'main', :desc => "The name of the stack to use"
|
58
|
+
method_option :variant, :type => :string, :default => 'default', :desc => "The variant to use, i.e default|scheduled|"
|
59
|
+
method_option :group, :type => :string, :default => nil, :desc => "The group name to override the component id"
|
60
|
+
method_option :project, :type => :string, :required => true, :desc => "The name of the project"
|
61
|
+
method_option :key_path, :type => :string, :default => ENV['DEV_CERT_PATH'], :desc => "The path to your dev cert, by default it looks in the env variable '$DEV_CERT_PATH'"
|
62
|
+
def update(component)
|
63
|
+
|
64
|
+
component_identifier = options[:group].nil? ? component : options[:group]
|
65
|
+
stack_name = "#{options[:env]}-#{component}-#{options[:stack]}"
|
66
|
+
|
67
|
+
data = cloudformation(component_identifier, options, false)
|
68
|
+
|
69
|
+
post_data = {
|
70
|
+
'template' => data,
|
71
|
+
'parameters' => Tools::Cloudformation::Generator.parameters(data)
|
72
|
+
}
|
73
|
+
|
74
|
+
@api = BBC::Cosmos::Tools::Config::API.new(config.app['api'], options[:key_path])
|
75
|
+
response = @api.post sprintf(config.app['stack_update_endpoint'], options[:env], component, stack_name), JSON.pretty_generate(post_data)
|
76
|
+
|
77
|
+
if response.success?
|
78
|
+
say "Stack update for component '#{component}' successfully started", :green
|
79
|
+
else
|
80
|
+
say "There was an error updating your stack: #{response.body}", :red
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def cloudformation(component, options, to_json = true)
|
88
|
+
config_data = config
|
89
|
+
|
90
|
+
Tools::Cloudformation::Generator.create(component, config, options, to_json) do
|
91
|
+
instance_eval config_data.cf_templates(component, options[:stack])
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,112 @@
|
|
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
|
+
|
7
|
+
module BBC
|
8
|
+
module Cosmos
|
9
|
+
module Tools
|
10
|
+
module Commands
|
11
|
+
class Config < Base
|
12
|
+
attr_accessor :cosmos_config
|
13
|
+
|
14
|
+
def initialize(args = [], local_options = {}, thor_config = {})
|
15
|
+
super(args, local_options, thor_config)
|
16
|
+
@cosmos_config = BBC::Cosmos::Tools::CosmosConfiguration.new(config)
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "config generate [COMPONENT]", "Generates config for the given component optionally in the cosmos format"
|
20
|
+
method_option :cosmos_format, :type => :boolean, :desc => "Toogles if the output should be in the cosmos format"
|
21
|
+
method_option :base, :type => :string, :desc => "The base path for the configs repo"
|
22
|
+
method_option :env, :type => :string, :default => 'int', :desc => "The environment to target"
|
23
|
+
method_option :project, :type => :string, :required => true, :desc => "The name of the project"
|
24
|
+
def generate(component)
|
25
|
+
begin
|
26
|
+
|
27
|
+
message = <<-output.gsub /^\s+/, ""
|
28
|
+
Component: #{component}
|
29
|
+
Project: #{options[:project]}
|
30
|
+
Environement: #{options[:env]}
|
31
|
+
output
|
32
|
+
|
33
|
+
say "\n#{message}\n", :green
|
34
|
+
|
35
|
+
if options[:cosmos_format]
|
36
|
+
say JSON.pretty_generate(cosmos_config.cosmos_component(component))
|
37
|
+
else
|
38
|
+
say JSON.pretty_generate(cosmos_config.component(component))
|
39
|
+
end
|
40
|
+
rescue Exception => e
|
41
|
+
error e.message
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "config list", "Lists all components for a given project"
|
47
|
+
method_option :base, :type => :string, :desc => "The base path for the configs repo"
|
48
|
+
method_option :env, :type => :string, :default => 'int', :desc => "The environment to target"
|
49
|
+
method_option :project, :type => :string, :required => true, :desc => "The name of the project"
|
50
|
+
def list
|
51
|
+
begin
|
52
|
+
|
53
|
+
message = <<-output.gsub /^\s+/, ""
|
54
|
+
Project: #{options[:project]}
|
55
|
+
Environement: #{options[:env]}
|
56
|
+
Components:
|
57
|
+
output
|
58
|
+
|
59
|
+
say "\n#{message}\n", :green
|
60
|
+
|
61
|
+
cosmos_config.components.keys.each do |component_id|
|
62
|
+
say "- #{component_id}", :blue
|
63
|
+
end
|
64
|
+
rescue Exception => e
|
65
|
+
error e.message
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
desc "config push [COMPONENT_ID = nil]", "Push config for a component to the cosmos API"
|
71
|
+
method_option :force, :type => :boolean, :desc => "This skips asking of you want to push the changes"
|
72
|
+
method_option :base, :type => :string, :desc => "The base path for the configs repo"
|
73
|
+
method_option :key_path, :type => :string, :default => ENV['DEV_CERT_PATH'], :desc => "The path to your dev cert, by default it looks in the env variable '$DEV_CERT_PATH'"
|
74
|
+
method_option :env, :type => :string, :default => 'int', :desc => "The environment to target"
|
75
|
+
method_option :project, :type => :string, :required => true, :desc => "The name of the project"
|
76
|
+
def push(component_id = nil)
|
77
|
+
begin
|
78
|
+
|
79
|
+
components = component_id.nil? ? cosmos_config.components : [component_id]
|
80
|
+
|
81
|
+
reply = yes?("Are you sure you want to push changes for #{components.length} components(s) to #{options[:env]}?", :blue) unless options[:force]
|
82
|
+
if reply || reply.nil?
|
83
|
+
|
84
|
+
components.each do |id|
|
85
|
+
component_config = JSON.generate(cosmos_config.cosmos_component id)
|
86
|
+
|
87
|
+
@api = BBC::Cosmos::Tools::API.new(config.app['api'], options[:key_path])
|
88
|
+
response = @api.put sprintf(config.app['config_endpoint'], options[:env], id), component_config
|
89
|
+
|
90
|
+
if response.success?
|
91
|
+
say "Configuration for component '#{id}' successfully saved", :green
|
92
|
+
else
|
93
|
+
say "There was an error saving your config: #{response.body}", :red
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
else
|
98
|
+
say "Action cancelled", :red
|
99
|
+
end
|
100
|
+
|
101
|
+
rescue Exception => e
|
102
|
+
puts e.backtrace
|
103
|
+
error e.message
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module BBC
|
4
|
+
module Cosmos
|
5
|
+
module Tools
|
6
|
+
class Config
|
7
|
+
attr_accessor :base_path, :project, :env
|
8
|
+
|
9
|
+
def initialize(base_path, project, env = 'int')
|
10
|
+
@base_path = base_path
|
11
|
+
@project = project
|
12
|
+
@env = env
|
13
|
+
end
|
14
|
+
|
15
|
+
def resources
|
16
|
+
if File.directory? File.join(base_path, 'resources', env)
|
17
|
+
path = File.join(base_path, 'resources', env, "#{project}.yaml")
|
18
|
+
if File.exist? path
|
19
|
+
YAML::load(File.open(path).read)
|
20
|
+
else
|
21
|
+
raise("#{project} doesn't exist")
|
22
|
+
end
|
23
|
+
else
|
24
|
+
raise("#{env} is an invalid environment")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def components
|
29
|
+
path = File.join(base_path, "configs", "#{project}.yaml.erb")
|
30
|
+
if File.exist? path
|
31
|
+
template = File.open(path).read
|
32
|
+
config = resources
|
33
|
+
YAML::load(
|
34
|
+
ERB.new(template).result(binding)
|
35
|
+
)['components']
|
36
|
+
else
|
37
|
+
raise("'#{project}' isn't valid project")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def app
|
42
|
+
config_path = base_path.join('configs', 'app.yaml')
|
43
|
+
raise("Invalid application config path: #{config_path}") unless File.exists? config_path
|
44
|
+
YAML::load(File.open(config_path).read)['bbc']['cosmos']
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def cf_templates(component, stack = 'main')
|
49
|
+
aws_templates = File.join(base_path, 'stacks', component, stack, '/aws/**/*.rb')
|
50
|
+
component_template = File.read(File.join(base_path, 'stacks', component, stack, 'template.rb'))
|
51
|
+
|
52
|
+
Dir
|
53
|
+
.glob(aws_templates)
|
54
|
+
.reduce(component_template) { |template_string, file| template_string += File.read(file) }
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'bbc/cosmos/tools/config'
|
3
|
+
|
4
|
+
module BBC
|
5
|
+
module Cosmos
|
6
|
+
module Tools
|
7
|
+
class CosmosConfiguration
|
8
|
+
attr_accessor :config
|
9
|
+
|
10
|
+
def initialize(config)
|
11
|
+
@config = config
|
12
|
+
end
|
13
|
+
|
14
|
+
def components
|
15
|
+
config.components
|
16
|
+
end
|
17
|
+
|
18
|
+
def component(id)
|
19
|
+
components[id].tap do |o|
|
20
|
+
raise("Invalid component id: #{id}") if o.nil?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def cosmos_component(id)
|
25
|
+
component(id).reduce([]) do |object, (key, value)|
|
26
|
+
object.tap { |o| o << {:value => value, :key => key} }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bbc-cosmos-tools
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Steven Jack
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: thor
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: faraday
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bbc-cfndsl
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: Tool for interacting with BBC Cosmos platform
|
84
|
+
email:
|
85
|
+
- stevenmajack@gmail.com
|
86
|
+
executables:
|
87
|
+
- bbc-cosmos-tools
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- .gitignore
|
92
|
+
- Gemfile
|
93
|
+
- LICENSE.txt
|
94
|
+
- README.md
|
95
|
+
- Rakefile
|
96
|
+
- bbc-cosmos-tools.gemspec
|
97
|
+
- bin/bbc-cosmos-tools
|
98
|
+
- lib/bbc/cosmos/tools.rb
|
99
|
+
- lib/bbc/cosmos/tools/api.rb
|
100
|
+
- lib/bbc/cosmos/tools/app.rb
|
101
|
+
- lib/bbc/cosmos/tools/cloudformation/generator.rb
|
102
|
+
- lib/bbc/cosmos/tools/commands/base.rb
|
103
|
+
- lib/bbc/cosmos/tools/commands/cloud_formation.rb
|
104
|
+
- lib/bbc/cosmos/tools/commands/config.rb
|
105
|
+
- lib/bbc/cosmos/tools/config.rb
|
106
|
+
- lib/bbc/cosmos/tools/cosmos_configuration.rb
|
107
|
+
- lib/bbc/cosmos/tools/version.rb
|
108
|
+
homepage: ''
|
109
|
+
licenses:
|
110
|
+
- MIT
|
111
|
+
metadata: {}
|
112
|
+
post_install_message:
|
113
|
+
rdoc_options: []
|
114
|
+
require_paths:
|
115
|
+
- lib
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
requirements: []
|
127
|
+
rubyforge_project:
|
128
|
+
rubygems_version: 2.0.3
|
129
|
+
signing_key:
|
130
|
+
specification_version: 4
|
131
|
+
summary: Tool for pusing config to cosmos and controlling cloudformation templates
|
132
|
+
test_files: []
|