formatron 0.1.0
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 +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.rubocop.yml +3 -0
- data/.simplecov +7 -0
- data/.travis.yml +17 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +6 -0
- data/Guardfile +16 -0
- data/LICENSE.txt +21 -0
- data/README.md +93 -0
- data/Rakefile +16 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/exe/formatron +20 -0
- data/formatron.gemspec +52 -0
- data/lib/formatron.rb +357 -0
- data/lib/formatron/aws.rb +197 -0
- data/lib/formatron/chef.rb +156 -0
- data/lib/formatron/chef/berkshelf.rb +55 -0
- data/lib/formatron/chef/keys.rb +48 -0
- data/lib/formatron/chef/knife.rb +169 -0
- data/lib/formatron/chef_clients.rb +73 -0
- data/lib/formatron/cli.rb +33 -0
- data/lib/formatron/cli/completion.rb +26 -0
- data/lib/formatron/cli/deploy.rb +57 -0
- data/lib/formatron/cli/destroy.rb +57 -0
- data/lib/formatron/cli/generators/bootstrap.rb +250 -0
- data/lib/formatron/cli/generators/credentials.rb +100 -0
- data/lib/formatron/cli/generators/instance.rb +118 -0
- data/lib/formatron/cli/provision.rb +59 -0
- data/lib/formatron/cloud_formation.rb +54 -0
- data/lib/formatron/cloud_formation/resources/cloud_formation.rb +27 -0
- data/lib/formatron/cloud_formation/resources/ec2.rb +336 -0
- data/lib/formatron/cloud_formation/resources/iam.rb +94 -0
- data/lib/formatron/cloud_formation/resources/route53.rb +54 -0
- data/lib/formatron/cloud_formation/scripts.rb +128 -0
- data/lib/formatron/cloud_formation/template.rb +114 -0
- data/lib/formatron/cloud_formation/template/parameters.rb +20 -0
- data/lib/formatron/cloud_formation/template/vpc.rb +181 -0
- data/lib/formatron/cloud_formation/template/vpc/subnet.rb +187 -0
- data/lib/formatron/cloud_formation/template/vpc/subnet/acl.rb +147 -0
- data/lib/formatron/cloud_formation/template/vpc/subnet/bastion.rb +66 -0
- data/lib/formatron/cloud_formation/template/vpc/subnet/chef_server.rb +205 -0
- data/lib/formatron/cloud_formation/template/vpc/subnet/instance.rb +162 -0
- data/lib/formatron/cloud_formation/template/vpc/subnet/instance/policy.rb +74 -0
- data/lib/formatron/cloud_formation/template/vpc/subnet/instance/security_group.rb +117 -0
- data/lib/formatron/cloud_formation/template/vpc/subnet/instance/setup.rb +68 -0
- data/lib/formatron/cloud_formation/template/vpc/subnet/nat.rb +94 -0
- data/lib/formatron/completion.rb +26 -0
- data/lib/formatron/completion/completion.sh.erb +35 -0
- data/lib/formatron/config.rb +31 -0
- data/lib/formatron/config/reader.rb +29 -0
- data/lib/formatron/dsl.rb +15 -0
- data/lib/formatron/dsl/formatron.rb +25 -0
- data/lib/formatron/dsl/formatron/global.rb +19 -0
- data/lib/formatron/dsl/formatron/global/ec2.rb +17 -0
- data/lib/formatron/dsl/formatron/vpc.rb +17 -0
- data/lib/formatron/dsl/formatron/vpc/subnet.rb +27 -0
- data/lib/formatron/dsl/formatron/vpc/subnet/acl.rb +18 -0
- data/lib/formatron/dsl/formatron/vpc/subnet/chef_server.rb +32 -0
- data/lib/formatron/dsl/formatron/vpc/subnet/chef_server/organization.rb +22 -0
- data/lib/formatron/dsl/formatron/vpc/subnet/instance.rb +29 -0
- data/lib/formatron/dsl/formatron/vpc/subnet/instance/chef.rb +22 -0
- data/lib/formatron/dsl/formatron/vpc/subnet/instance/policy.rb +21 -0
- data/lib/formatron/dsl/formatron/vpc/subnet/instance/policy/statement.rb +23 -0
- data/lib/formatron/dsl/formatron/vpc/subnet/instance/security_group.rb +21 -0
- data/lib/formatron/dsl/formatron/vpc/subnet/instance/setup.rb +22 -0
- data/lib/formatron/dsl/formatron/vpc/subnet/instance/setup/variable.rb +23 -0
- data/lib/formatron/external.rb +61 -0
- data/lib/formatron/external/dsl.rb +171 -0
- data/lib/formatron/external/outputs.rb +25 -0
- data/lib/formatron/generators/bootstrap.rb +90 -0
- data/lib/formatron/generators/bootstrap/config.rb +62 -0
- data/lib/formatron/generators/bootstrap/ec2.rb +17 -0
- data/lib/formatron/generators/bootstrap/formatronfile.rb +52 -0
- data/lib/formatron/generators/bootstrap/formatronfile/Formatronfile.erb +79 -0
- data/lib/formatron/generators/bootstrap/ssl.rb +35 -0
- data/lib/formatron/generators/credentials.rb +17 -0
- data/lib/formatron/generators/instance.rb +64 -0
- data/lib/formatron/generators/instance/config.rb +47 -0
- data/lib/formatron/generators/instance/formatronfile.rb +47 -0
- data/lib/formatron/generators/instance/formatronfile/Formatronfile.erb +16 -0
- data/lib/formatron/generators/util.rb +14 -0
- data/lib/formatron/generators/util/cookbook.rb +65 -0
- data/lib/formatron/generators/util/gitignore.rb +16 -0
- data/lib/formatron/generators/util/readme.rb +18 -0
- data/lib/formatron/logger.rb +8 -0
- data/lib/formatron/s3/chef_server_cert.rb +85 -0
- data/lib/formatron/s3/chef_server_keys.rb +103 -0
- data/lib/formatron/s3/cloud_formation_template.rb +61 -0
- data/lib/formatron/s3/configuration.rb +58 -0
- data/lib/formatron/s3/path.rb +30 -0
- data/lib/formatron/util/dsl.rb +107 -0
- data/lib/formatron/util/shell.rb +20 -0
- data/lib/formatron/util/vpc.rb +15 -0
- data/lib/formatron/version.rb +4 -0
- data/support/cloudformation_describe_stacks_response.rb +36 -0
- data/support/dsl_test.rb +123 -0
- data/support/route53_get_hosted_zone_response.rb +21 -0
- data/support/s3_get_object_response.rb +21 -0
- data/support/template_test.rb +41 -0
- metadata +414 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
require 'formatron/util/shell'
|
|
2
|
+
require 'English'
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
class Formatron
|
|
6
|
+
class Chef
|
|
7
|
+
# Wrapper for the knife cli
|
|
8
|
+
# rubocop:disable Metrics/ClassLength
|
|
9
|
+
class Knife
|
|
10
|
+
# rubocop:disable Metrics/MethodLength
|
|
11
|
+
# rubocop:disable Metrics/ParameterLists
|
|
12
|
+
def initialize(
|
|
13
|
+
keys:,
|
|
14
|
+
chef_server_url:,
|
|
15
|
+
username:,
|
|
16
|
+
organization:,
|
|
17
|
+
ssl_verify:,
|
|
18
|
+
name:,
|
|
19
|
+
databag_secret:,
|
|
20
|
+
configuration:
|
|
21
|
+
)
|
|
22
|
+
@keys = keys
|
|
23
|
+
@chef_server_url = chef_server_url
|
|
24
|
+
@username = username
|
|
25
|
+
@organization = organization
|
|
26
|
+
@ssl_verify = ssl_verify
|
|
27
|
+
@name = name
|
|
28
|
+
@databag_secret = databag_secret
|
|
29
|
+
@configuration = configuration
|
|
30
|
+
end
|
|
31
|
+
# rubocop:enable Metrics/ParameterLists
|
|
32
|
+
# rubocop:enable Metrics/MethodLength
|
|
33
|
+
|
|
34
|
+
# rubocop:disable Metrics/MethodLength
|
|
35
|
+
def init
|
|
36
|
+
@knife_file = Tempfile.new 'formatron-knife-'
|
|
37
|
+
@knife_file.write <<-EOH.gsub(/^ {10}/, '')
|
|
38
|
+
chef_server_url '#{@chef_server_url}'
|
|
39
|
+
validation_client_name '#{@organization}-validator'
|
|
40
|
+
validation_key '#{@keys.organization_key}'
|
|
41
|
+
node_name '#{@username}'
|
|
42
|
+
client_key '#{@keys.user_key}'
|
|
43
|
+
verify_api_cert #{@ssl_verify}
|
|
44
|
+
ssl_verify_mode #{@ssl_verify ? ':verify_peer' : ':verify_none'}
|
|
45
|
+
EOH
|
|
46
|
+
@knife_file.close
|
|
47
|
+
@databag_secret_file = Tempfile.new 'formatron-databag-secret-'
|
|
48
|
+
@databag_secret_file.write @databag_secret
|
|
49
|
+
@databag_secret_file.close
|
|
50
|
+
@databag_file = Tempfile.new ['formatron-databag-', '.json']
|
|
51
|
+
@databag_file.write @configuration.merge(id: @name).to_json
|
|
52
|
+
@databag_file.close
|
|
53
|
+
end
|
|
54
|
+
# rubocop:enable Metrics/MethodLength
|
|
55
|
+
|
|
56
|
+
def deploy_databag
|
|
57
|
+
_attempt_to_create_databag unless _databag_exists
|
|
58
|
+
_attempt_to_create_databag_item
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def _databag_exists
|
|
62
|
+
Util::Shell.exec "knife data bag show formatron -c #{@knife_file.path}"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def _attempt_to_create_databag
|
|
66
|
+
fail 'failed to create data bag: formatron' unless _create_databag
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def _create_databag
|
|
70
|
+
# rubocop:disable Metrics/LineLength
|
|
71
|
+
Util::Shell.exec "knife data bag create formatron -c #{@knife_file.path}"
|
|
72
|
+
# rubocop:enable Metrics/LineLength
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def _attempt_to_create_databag_item
|
|
76
|
+
# rubocop:disable Metrics/LineLength
|
|
77
|
+
fail "failed to create data bag item: #{@name}" unless _create_databag_item
|
|
78
|
+
# rubocop:enable Metrics/LineLength
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def _create_databag_item
|
|
82
|
+
# rubocop:disable Metrics/LineLength
|
|
83
|
+
Util::Shell.exec "knife data bag from file formatron #{@databag_file.path} --secret-file #{@databag_secret_file.path} -c #{@knife_file.path}"
|
|
84
|
+
# rubocop:enable Metrics/LineLength
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def create_environment(environment:)
|
|
88
|
+
# rubocop:disable Metrics/LineLength
|
|
89
|
+
_attempt_to_create_environment environment unless _environment_exists environment
|
|
90
|
+
# rubocop:enable Metrics/LineLength
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def _environment_exists(environment)
|
|
94
|
+
# rubocop:disable Metrics/LineLength
|
|
95
|
+
Util::Shell.exec "knife environment show #{environment} -c #{@knife_file.path}"
|
|
96
|
+
# rubocop:enable Metrics/LineLength
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def _attempt_to_create_environment(environment)
|
|
100
|
+
# rubocop:disable Metrics/LineLength
|
|
101
|
+
fail "failed to create opscode environment: #{environment}" unless _create_environment environment
|
|
102
|
+
# rubocop:enable Metrics/LineLength
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def _create_environment(environment)
|
|
106
|
+
# rubocop:disable Metrics/LineLength
|
|
107
|
+
Util::Shell.exec "knife environment create #{environment} -c #{@knife_file.path} -d '#{environment} environment created by formatron'"
|
|
108
|
+
# rubocop:enable Metrics/LineLength
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def bootstrap(
|
|
112
|
+
environment:,
|
|
113
|
+
bastion_hostname:,
|
|
114
|
+
cookbook:,
|
|
115
|
+
hostname:
|
|
116
|
+
)
|
|
117
|
+
# rubocop:disable Metrics/LineLength
|
|
118
|
+
command = "knife bootstrap #{hostname} --sudo -x ubuntu -i #{@keys.ec2_key} -E #{environment} -r #{cookbook} -N #{environment} -c #{@knife_file.path}#{@ssl_verify ? '' : ' --node-ssl-verify-mode none'} --secret-file #{@databag_secret_file.path}"
|
|
119
|
+
command = "#{command} -G ubuntu@#{bastion_hostname}" unless bastion_hostname.eql? hostname
|
|
120
|
+
fail "failed to bootstrap instance: #{hostname}" unless Util::Shell.exec command
|
|
121
|
+
# rubocop:enable Metrics/LineLength
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def delete_databag
|
|
125
|
+
# rubocop:disable Metrics/LineLength
|
|
126
|
+
command = "knife data bag delete formatron #{@name} -y -c #{@knife_file.path}"
|
|
127
|
+
fail "failed to delete data bag item: #{@name}" unless Util::Shell.exec command
|
|
128
|
+
# rubocop:enable Metrics/LineLength
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def delete_node(node:)
|
|
132
|
+
command = "knife node delete #{node} -y -c #{@knife_file.path}"
|
|
133
|
+
fail "failed to delete node: #{node}" unless Util::Shell.exec command
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def delete_client(client:)
|
|
137
|
+
# rubocop:disable Metrics/LineLength
|
|
138
|
+
command = "knife client delete #{client} -y -c #{@knife_file.path}"
|
|
139
|
+
fail "failed to delete client: #{client}" unless Util::Shell.exec command
|
|
140
|
+
# rubocop:enable Metrics/LineLength
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def delete_environment(environment:)
|
|
144
|
+
# rubocop:disable Metrics/LineLength
|
|
145
|
+
command = "knife environment delete #{environment} -y -c #{@knife_file.path}"
|
|
146
|
+
fail "failed to delete environment: #{environment}" unless Util::Shell.exec command
|
|
147
|
+
# rubocop:enable Metrics/LineLength
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def unlink
|
|
151
|
+
@knife_file.unlink unless @knife_file.nil?
|
|
152
|
+
@databag_secret_file.unlink unless @databag_secret_file.nil?
|
|
153
|
+
@databag_file.unlink unless @databag_file.nil?
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
private(
|
|
157
|
+
:_create_databag,
|
|
158
|
+
:_create_databag_item,
|
|
159
|
+
:_attempt_to_create_databag,
|
|
160
|
+
:_attempt_to_create_databag_item,
|
|
161
|
+
:_databag_exists,
|
|
162
|
+
:_create_environment,
|
|
163
|
+
:_attempt_to_create_environment,
|
|
164
|
+
:_environment_exists
|
|
165
|
+
)
|
|
166
|
+
end
|
|
167
|
+
# rubocop:enable Metrics/ClassLength
|
|
168
|
+
end
|
|
169
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
class Formatron
|
|
2
|
+
# creates chef clients
|
|
3
|
+
class ChefClients
|
|
4
|
+
# rubocop:disable Metrics/ParameterLists
|
|
5
|
+
# rubocop:disable Metrics/AbcSize
|
|
6
|
+
# rubocop:disable Metrics/MethodLength
|
|
7
|
+
def initialize(
|
|
8
|
+
aws:,
|
|
9
|
+
bucket:,
|
|
10
|
+
name:,
|
|
11
|
+
target:,
|
|
12
|
+
ec2_key:,
|
|
13
|
+
hosted_zone_name:,
|
|
14
|
+
vpc:,
|
|
15
|
+
external:,
|
|
16
|
+
configuration:,
|
|
17
|
+
databag_secret:
|
|
18
|
+
)
|
|
19
|
+
@chef_clients = {}
|
|
20
|
+
if external.nil?
|
|
21
|
+
bastions = Util::VPC.instances :bastion, vpc
|
|
22
|
+
chef_servers = Util::VPC.instances :chef_server, vpc
|
|
23
|
+
else
|
|
24
|
+
bastions = Util::VPC.instances :bastion, external, vpc
|
|
25
|
+
chef_servers = Util::VPC.instances :chef_server, external, vpc
|
|
26
|
+
end
|
|
27
|
+
bastions = Hash[bastions.map { |k, v| [k, v.sub_domain] }]
|
|
28
|
+
chef_servers.each do |key, chef_server|
|
|
29
|
+
@chef_clients[key] = Chef.new(
|
|
30
|
+
aws: aws,
|
|
31
|
+
bucket: bucket,
|
|
32
|
+
name: name,
|
|
33
|
+
target: target,
|
|
34
|
+
username: chef_server.username,
|
|
35
|
+
organization: chef_server.organization.short_name,
|
|
36
|
+
ssl_verify: chef_server.ssl_verify,
|
|
37
|
+
chef_sub_domain: chef_server.sub_domain,
|
|
38
|
+
ec2_key: ec2_key,
|
|
39
|
+
bastions: bastions,
|
|
40
|
+
hosted_zone_name: hosted_zone_name,
|
|
41
|
+
server_stack: chef_server.stack || name,
|
|
42
|
+
guid: chef_server.guid,
|
|
43
|
+
configuration: configuration,
|
|
44
|
+
databag_secret: databag_secret
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
# rubocop:enable Metrics/MethodLength
|
|
49
|
+
# rubocop:enable Metrics/AbcSize
|
|
50
|
+
# rubocop:enable Metrics/ParameterLists
|
|
51
|
+
|
|
52
|
+
def get(key = nil)
|
|
53
|
+
key ||= @chef_clients.keys[0]
|
|
54
|
+
@chef_clients[key]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def init
|
|
58
|
+
@chef_clients.values.each(&:init)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def unlink
|
|
62
|
+
@chef_clients.values.each(&:unlink)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def deploy_databags
|
|
66
|
+
@chef_clients.values.each(&:deploy_databag)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def delete_databags
|
|
70
|
+
@chef_clients.values.each(&:delete_databag)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'commander'
|
|
2
|
+
require 'formatron/version'
|
|
3
|
+
|
|
4
|
+
class Formatron
|
|
5
|
+
# CLI interface
|
|
6
|
+
class CLI
|
|
7
|
+
include Commander::Methods
|
|
8
|
+
|
|
9
|
+
def global_options
|
|
10
|
+
global_option '-c', '--credentials FILE', 'The credentials file'
|
|
11
|
+
global_option(
|
|
12
|
+
'-d',
|
|
13
|
+
'--directory DIRECTORY',
|
|
14
|
+
'The Formatron configuration directory'
|
|
15
|
+
)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def commands
|
|
19
|
+
self.class.instance_methods.each do |method|
|
|
20
|
+
send(method) if method =~ /_formatron_command$/
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def run
|
|
25
|
+
program :version, Formatron::VERSION
|
|
26
|
+
program :description, 'Quickly deploy AWS CloudFormation ' \
|
|
27
|
+
'stacks backed by a Chef Server'
|
|
28
|
+
global_options
|
|
29
|
+
commands
|
|
30
|
+
run!
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'formatron/completion'
|
|
2
|
+
|
|
3
|
+
class Formatron
|
|
4
|
+
class CLI
|
|
5
|
+
# CLI command for completion enabling script
|
|
6
|
+
module Completion
|
|
7
|
+
def completion_script_action(c)
|
|
8
|
+
c.action do |args|
|
|
9
|
+
command = args[0] || 'formatron'
|
|
10
|
+
print Formatron::Completion.script command, defined_commands.keys
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def completion_script_formatron_command
|
|
15
|
+
command :'completion-script' do |c|
|
|
16
|
+
c.syntax = 'formatron completion-script [COMMAND]'
|
|
17
|
+
c.summary = 'Output a bash script to ' \
|
|
18
|
+
'enable command completion'
|
|
19
|
+
c.description = 'Output a bash script to ' \
|
|
20
|
+
'enable command completion'
|
|
21
|
+
completion_script_action c
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'formatron/config'
|
|
2
|
+
require 'formatron'
|
|
3
|
+
|
|
4
|
+
class Formatron
|
|
5
|
+
class CLI
|
|
6
|
+
# CLI command for deploy
|
|
7
|
+
module Deploy
|
|
8
|
+
def deploy_directory(options)
|
|
9
|
+
options.directory || Dir.pwd
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def deploy_credentials(options)
|
|
13
|
+
options.credentials ||
|
|
14
|
+
Generators::Credentials.default_credentials(
|
|
15
|
+
deploy_directory(options)
|
|
16
|
+
)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def deploy_target(target, directory)
|
|
20
|
+
target || choose(
|
|
21
|
+
'Target?',
|
|
22
|
+
*Config.targets(directory: directory)
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def deploy_ok(formatron, target)
|
|
27
|
+
!formatron.protected? || agree(
|
|
28
|
+
"Are you sure you wish to deploy protected target: #{target}?"
|
|
29
|
+
) do |q|
|
|
30
|
+
q.default = 'no'
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def deploy_action(c)
|
|
35
|
+
c.action do |args, options|
|
|
36
|
+
directory = deploy_directory options
|
|
37
|
+
target = deploy_target args[0], directory
|
|
38
|
+
formatron = Formatron.new(
|
|
39
|
+
credentials: deploy_credentials(options),
|
|
40
|
+
directory: directory,
|
|
41
|
+
target: target
|
|
42
|
+
)
|
|
43
|
+
formatron.deploy if deploy_ok(formatron, target)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def deploy_formatron_command
|
|
48
|
+
command :deploy do |c|
|
|
49
|
+
c.syntax = 'formatron deploy [options] [TARGET]'
|
|
50
|
+
c.summary = 'Deploy or update a Formatron stack'
|
|
51
|
+
c.description = 'Deploy or update a Formatron stack'
|
|
52
|
+
deploy_action c
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'formatron'
|
|
2
|
+
require 'formatron/config'
|
|
3
|
+
|
|
4
|
+
class Formatron
|
|
5
|
+
class CLI
|
|
6
|
+
# CLI command for destroy
|
|
7
|
+
module Destroy
|
|
8
|
+
def destroy_directory(options)
|
|
9
|
+
options.directory || Dir.pwd
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def destroy_credentials(options)
|
|
13
|
+
options.credentials ||
|
|
14
|
+
Generators::Credentials.default_credentials(
|
|
15
|
+
destroy_directory(options)
|
|
16
|
+
)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def destroy_target(target, directory)
|
|
20
|
+
target || choose(
|
|
21
|
+
'Target?',
|
|
22
|
+
*Config.targets(directory: directory)
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def destroy_ok(formatron, target)
|
|
27
|
+
!formatron.protected? || agree(
|
|
28
|
+
"Are you sure you wish to destroy protected target: #{target}?"
|
|
29
|
+
) do |q|
|
|
30
|
+
q.default = 'no'
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def destroy_action(c)
|
|
35
|
+
c.action do |args, options|
|
|
36
|
+
directory = destroy_directory options
|
|
37
|
+
target = destroy_target args[0], directory
|
|
38
|
+
formatron = Formatron.new(
|
|
39
|
+
credentials: destroy_credentials(options),
|
|
40
|
+
directory: directory,
|
|
41
|
+
target: target
|
|
42
|
+
)
|
|
43
|
+
formatron.destroy if destroy_ok formatron, target
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def destroy_formatron_command
|
|
48
|
+
command :destroy do |c|
|
|
49
|
+
c.syntax = 'formatron destroy [options] [TARGET]'
|
|
50
|
+
c.summary = 'Destroy a Formatron stack'
|
|
51
|
+
c.description = 'Destroy a Formatron stack'
|
|
52
|
+
destroy_action c
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
require 'formatron/generators/bootstrap'
|
|
2
|
+
|
|
3
|
+
class Formatron
|
|
4
|
+
class CLI
|
|
5
|
+
module Generators
|
|
6
|
+
# CLI command for bootstrap generator
|
|
7
|
+
# rubocop:disable Metrics/ModuleLength
|
|
8
|
+
module Bootstrap
|
|
9
|
+
# rubocop:disable Metrics/MethodLength
|
|
10
|
+
# rubocop:disable Metrics/AbcSize
|
|
11
|
+
def bootstrap_options(c)
|
|
12
|
+
c.option '-n', '--name STRING', 'The name for the configuration'
|
|
13
|
+
c.option(
|
|
14
|
+
'-s',
|
|
15
|
+
'--s3-bucket STRING',
|
|
16
|
+
'The S3 bucket to store encrypted configuration'
|
|
17
|
+
)
|
|
18
|
+
c.option(
|
|
19
|
+
'-k',
|
|
20
|
+
'--kms-key STRING',
|
|
21
|
+
'The KMS key to use for encryption'
|
|
22
|
+
)
|
|
23
|
+
c.option(
|
|
24
|
+
'-e',
|
|
25
|
+
'--ec2-key-pair STRING',
|
|
26
|
+
'The EC2 key pair to associate with EC2 instances'
|
|
27
|
+
)
|
|
28
|
+
c.option(
|
|
29
|
+
'-z',
|
|
30
|
+
'--hosted-zone-id STRING',
|
|
31
|
+
'The Route53 Hosted Zone ID for the public hosted zone'
|
|
32
|
+
)
|
|
33
|
+
c.option(
|
|
34
|
+
'-a',
|
|
35
|
+
'--availability-zone STRING',
|
|
36
|
+
'The AWS availability zone letter (region is already taken ' \
|
|
37
|
+
'from the AWS credentials)'
|
|
38
|
+
)
|
|
39
|
+
c.option(
|
|
40
|
+
'-b',
|
|
41
|
+
'--cookbooks-bucket-prefix STRING',
|
|
42
|
+
'Used to generate target specific S3 bucket names ' \
|
|
43
|
+
'(PREFIX-TARGET) for the Chef Server to store its ' \
|
|
44
|
+
'cookbook library'
|
|
45
|
+
)
|
|
46
|
+
c.option(
|
|
47
|
+
'-o',
|
|
48
|
+
'--organization-short-name STRING',
|
|
49
|
+
'The short name of the organization to create on the ' \
|
|
50
|
+
'Chef Server (should not contain spaces, etc)'
|
|
51
|
+
)
|
|
52
|
+
c.option(
|
|
53
|
+
'-w',
|
|
54
|
+
'--organization-full-name STRING',
|
|
55
|
+
'The full name of the organization to create on the Chef Server'
|
|
56
|
+
)
|
|
57
|
+
c.option(
|
|
58
|
+
'-u',
|
|
59
|
+
'--username STRING',
|
|
60
|
+
'The username to create on the Chef Server'
|
|
61
|
+
)
|
|
62
|
+
c.option(
|
|
63
|
+
'-p',
|
|
64
|
+
'--password STRING',
|
|
65
|
+
'The password for the Chef Server user'
|
|
66
|
+
)
|
|
67
|
+
c.option(
|
|
68
|
+
'-m',
|
|
69
|
+
'--email STRING',
|
|
70
|
+
'The email address for the Chef Server user'
|
|
71
|
+
)
|
|
72
|
+
c.option(
|
|
73
|
+
'-f',
|
|
74
|
+
'--first-name STRING',
|
|
75
|
+
'The first name of the Chef Server user'
|
|
76
|
+
)
|
|
77
|
+
c.option(
|
|
78
|
+
'-l',
|
|
79
|
+
'--last-name STRING',
|
|
80
|
+
'The last name of the Chef Server user'
|
|
81
|
+
)
|
|
82
|
+
c.option(
|
|
83
|
+
'-i',
|
|
84
|
+
'--instance-cookbook STRING',
|
|
85
|
+
'The instance cookbook to apply additional ' \
|
|
86
|
+
'configuration to the Chef Server'
|
|
87
|
+
)
|
|
88
|
+
c.option(
|
|
89
|
+
'-x',
|
|
90
|
+
'--protected-targets LIST',
|
|
91
|
+
Array,
|
|
92
|
+
'The protected targets (eg. production)'
|
|
93
|
+
)
|
|
94
|
+
c.option(
|
|
95
|
+
'-y',
|
|
96
|
+
'--unprotected-targets LIST',
|
|
97
|
+
Array,
|
|
98
|
+
'The unprotected targets (eg. test)'
|
|
99
|
+
)
|
|
100
|
+
end
|
|
101
|
+
# rubocop:enable Metrics/AbcSize
|
|
102
|
+
# rubocop:enable Metrics/MethodLength
|
|
103
|
+
|
|
104
|
+
def bootstrap_directory(options)
|
|
105
|
+
options.directory || ask('Directory? ') do |q|
|
|
106
|
+
q.default = Dir.pwd
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def bootstrap_name(options, directory)
|
|
111
|
+
options.name || ask('Name? ') do |q|
|
|
112
|
+
q.default = File.basename directory
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def bootstrap_s3_bucket(options)
|
|
117
|
+
options.s3_bucket || ask('S3 Bucket? ')
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def bootstrap_kms_key(options)
|
|
121
|
+
options.kms_key || ask('KMS Key? ')
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def bootstrap_ec2_key_pair(options)
|
|
125
|
+
options.ec2_key_pair || ask('EC2 Key Pair? ')
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def bootstrap_hosted_zone_id(options)
|
|
129
|
+
options.hosted_zone_id || ask('Hosted Zone ID? ')
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def bootstrap_availability_zone(options)
|
|
133
|
+
options.availability_zone || ask('Availability Zone? ')
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def bootstrap_cookbooks_bucket_prefix(options)
|
|
137
|
+
options.cookbooks_bucket_prefix || ask(
|
|
138
|
+
'Chef Server Cookbooks Bucket Prefix? '
|
|
139
|
+
) do |q|
|
|
140
|
+
q.default = "#{options.s3_bucket}-cookbooks"
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def bootstrap_organization_short_name(options)
|
|
145
|
+
options.organization_short_name ||
|
|
146
|
+
ask('Chef Server Organization Short Name? ')
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def bootstrap_organization_full_name(options)
|
|
150
|
+
options.organization_full_name ||
|
|
151
|
+
ask('Chef Server Organization Full Name? ')
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def bootstrap_username(options)
|
|
155
|
+
options.username || ask('Chef Server Username? ')
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def bootstrap_password(options)
|
|
159
|
+
options.password || password('Chef Server Password? ')
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def bootstrap_email(options)
|
|
163
|
+
options.email || ask('Chef Server User Email? ')
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def bootstrap_first_name(options)
|
|
167
|
+
options.first_name || ask('Chef Server User First Name? ')
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def bootstrap_last_name(options)
|
|
171
|
+
options.last_name || ask('Chef Server User Last Name? ')
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def bootstrap_protected_targets(options)
|
|
175
|
+
options.protected_targets || ask('Protected Targets? ', Array) do |q|
|
|
176
|
+
q.default = 'production'
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def bootstrap_unprotected_targets(options)
|
|
181
|
+
options.unprotected_targets ||
|
|
182
|
+
ask('Unprotected Targets? ', Array) do |q|
|
|
183
|
+
q.default = 'test'
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def bootstrap_targets(options)
|
|
188
|
+
protected_targets = bootstrap_protected_targets options
|
|
189
|
+
unprotected_targets = bootstrap_unprotected_targets options
|
|
190
|
+
targets = {}
|
|
191
|
+
protected_targets.each do |target|
|
|
192
|
+
targets[target.to_sym] = { protect: true }
|
|
193
|
+
end
|
|
194
|
+
unprotected_targets.each do |target|
|
|
195
|
+
targets[target.to_sym] = { protect: false }
|
|
196
|
+
end
|
|
197
|
+
targets
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# rubocop:disable Metrics/MethodLength
|
|
201
|
+
def bootstrap_params(options, directory)
|
|
202
|
+
{
|
|
203
|
+
name: bootstrap_name(options, directory),
|
|
204
|
+
s3_bucket: bootstrap_s3_bucket(options),
|
|
205
|
+
kms_key: bootstrap_kms_key(options),
|
|
206
|
+
ec2_key_pair: bootstrap_ec2_key_pair(options),
|
|
207
|
+
hosted_zone_id: bootstrap_hosted_zone_id(options),
|
|
208
|
+
availability_zone: bootstrap_availability_zone(options),
|
|
209
|
+
chef_server: {
|
|
210
|
+
cookbooks_bucket_prefix:
|
|
211
|
+
bootstrap_cookbooks_bucket_prefix(options),
|
|
212
|
+
organization: {
|
|
213
|
+
short_name: bootstrap_organization_short_name(options),
|
|
214
|
+
full_name: bootstrap_organization_full_name(options)
|
|
215
|
+
},
|
|
216
|
+
username: bootstrap_username(options),
|
|
217
|
+
password: bootstrap_password(options),
|
|
218
|
+
email: bootstrap_email(options),
|
|
219
|
+
first_name: bootstrap_first_name(options),
|
|
220
|
+
last_name: bootstrap_last_name(options)
|
|
221
|
+
},
|
|
222
|
+
targets: bootstrap_targets(options)
|
|
223
|
+
}
|
|
224
|
+
end
|
|
225
|
+
# rubocop:enable Metrics/MethodLength
|
|
226
|
+
|
|
227
|
+
def bootstrap_action(c)
|
|
228
|
+
c.action do |_args, options|
|
|
229
|
+
directory = bootstrap_directory options
|
|
230
|
+
Formatron::Generators::Bootstrap.generate(
|
|
231
|
+
directory,
|
|
232
|
+
bootstrap_params(options, directory)
|
|
233
|
+
)
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def bootstrap_formatron_command
|
|
238
|
+
command :'generate bootstrap' do |c|
|
|
239
|
+
c.syntax = 'formatron generate bootstrap [options]'
|
|
240
|
+
c.summary = 'Generate a bootstrap configuration'
|
|
241
|
+
c.description = 'Generate a bootstrap configuration'
|
|
242
|
+
bootstrap_options c
|
|
243
|
+
bootstrap_action c
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
# rubocop:enable Metrics/ModuleLength
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
end
|