fhcap-cli 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rakeTasks +7 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +15 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +150 -0
- data/Rakefile +2 -0
- data/bin/fhcap +6 -0
- data/fhcap-cli.gemspec +44 -0
- data/lib/cookbooks/provision/libraries/provision.rb +140 -0
- data/lib/cookbooks/provision/metadata.rb +7 -0
- data/lib/cookbooks/provision/recipes/aws.rb +15 -0
- data/lib/cookbooks/provision/recipes/aws_cluster_create.rb +59 -0
- data/lib/cookbooks/provision/recipes/aws_cluster_create_elb.rb +61 -0
- data/lib/cookbooks/provision/recipes/aws_cluster_destroy.rb +52 -0
- data/lib/cookbooks/provision/recipes/cluster_create.rb +2 -0
- data/lib/cookbooks/provision/recipes/cluster_destroy.rb +2 -0
- data/lib/cookbooks/provision/recipes/cluster_destroy_instances.rb +11 -0
- data/lib/cookbooks/provision/recipes/cluster_provision.rb +4 -0
- data/lib/cookbooks/provision/recipes/cluster_provision_instances.rb +55 -0
- data/lib/cookbooks/provision/recipes/cluster_status.rb +24 -0
- data/lib/cookbooks/provision/recipes/common.rb +9 -0
- data/lib/cookbooks/provision/recipes/default.rb +5 -0
- data/lib/cookbooks/provision/recipes/openstack.rb +11 -0
- data/lib/cookbooks/provision/recipes/openstack_cluster_create.rb +11 -0
- data/lib/cookbooks/provision/recipes/openstack_cluster_destroy.rb +4 -0
- data/lib/cookbooks/provision/recipes/reset_rabbitmq.rb +49 -0
- data/lib/cookbooks/provision/recipes/restart_services.rb +24 -0
- data/lib/extensions/chef/provisioning.rb +21 -0
- data/lib/extensions/chef/provisioning/aws_driver/driver.rb +46 -0
- data/lib/extensions/chef/provisioning/chef_run_data.rb +18 -0
- data/lib/extensions/cheffish/merged_config.rb +9 -0
- data/lib/fhcap.rb +14 -0
- data/lib/fhcap/chef-dk/chef_runner.rb +94 -0
- data/lib/fhcap/cli.rb +75 -0
- data/lib/fhcap/cluster.rb +112 -0
- data/lib/fhcap/config.rb +104 -0
- data/lib/fhcap/cookbook.rb +75 -0
- data/lib/fhcap/dummy_node.rb +80 -0
- data/lib/fhcap/fhcap_helper.rb +9 -0
- data/lib/fhcap/kitchen.rb +235 -0
- data/lib/fhcap/knife.rb +74 -0
- data/lib/fhcap/knife_helper.rb +38 -0
- data/lib/fhcap/misc.rb +103 -0
- data/lib/fhcap/provider.rb +41 -0
- data/lib/fhcap/providers_helper.rb +60 -0
- data/lib/fhcap/repo.rb +52 -0
- data/lib/fhcap/repos_helper.rb +217 -0
- data/lib/fhcap/tasks/chef/chef_task_base.rb +82 -0
- data/lib/fhcap/tasks/chef/cookbook/list.rb +37 -0
- data/lib/fhcap/tasks/chef/cookbook/update_changelog.rb +63 -0
- data/lib/fhcap/tasks/chef/cookbook/update_metadata.rb +57 -0
- data/lib/fhcap/tasks/chef/cookbook/update_readme.rb +30 -0
- data/lib/fhcap/tasks/chef/cookbook/update_version.rb +90 -0
- data/lib/fhcap/tasks/chef/environments/create.rb +115 -0
- data/lib/fhcap/tasks/chef/environments/destroy.rb +37 -0
- data/lib/fhcap/tasks/chef/environments/promote_cookbooks.rb +47 -0
- data/lib/fhcap/tasks/chef/provisioning/chef_provisioning_task.rb +27 -0
- data/lib/fhcap/tasks/chef/provisioning/chef_provisioning_task_base.rb +38 -0
- data/lib/fhcap/tasks/chef/provisioning/create.rb +22 -0
- data/lib/fhcap/tasks/chef/provisioning/destroy.rb +21 -0
- data/lib/fhcap/tasks/chef/provisioning/provision.rb +19 -0
- data/lib/fhcap/tasks/chef/server/bootstrap.rb +165 -0
- data/lib/fhcap/tasks/chef/server/create_user.rb +97 -0
- data/lib/fhcap/tasks/chef/server/info.rb +82 -0
- data/lib/fhcap/tasks/chef/server/provision.rb +45 -0
- data/lib/fhcap/tasks/clean.rb +34 -0
- data/lib/fhcap/tasks/cluster/cluster_task_base.rb +57 -0
- data/lib/fhcap/tasks/cluster/create.rb +243 -0
- data/lib/fhcap/tasks/cluster/create_environment.rb +171 -0
- data/lib/fhcap/tasks/cluster/destroy.rb +30 -0
- data/lib/fhcap/tasks/cluster/destroy_environment.rb +28 -0
- data/lib/fhcap/tasks/cluster/info.rb +67 -0
- data/lib/fhcap/tasks/cluster/list.rb +40 -0
- data/lib/fhcap/tasks/cluster/provision.rb +46 -0
- data/lib/fhcap/tasks/cluster/status.rb +17 -0
- data/lib/fhcap/tasks/cluster/test.rb +15 -0
- data/lib/fhcap/tasks/knife/add.rb +111 -0
- data/lib/fhcap/tasks/knife/list.rb +22 -0
- data/lib/fhcap/tasks/knife/remove.rb +39 -0
- data/lib/fhcap/tasks/misc/create_dns_record.rb +100 -0
- data/lib/fhcap/tasks/misc/create_ssl_cert.rb +82 -0
- data/lib/fhcap/tasks/provider/add.rb +136 -0
- data/lib/fhcap/tasks/provider/list.rb +31 -0
- data/lib/fhcap/tasks/provider/remove.rb +28 -0
- data/lib/fhcap/tasks/repo/add.rb +57 -0
- data/lib/fhcap/tasks/repo/checkout.rb +144 -0
- data/lib/fhcap/tasks/repo/list.rb +22 -0
- data/lib/fhcap/tasks/repo/remove.rb +34 -0
- data/lib/fhcap/tasks/setup.rb +59 -0
- data/lib/fhcap/tasks/task_base.rb +89 -0
- data/lib/fhcap/thor_base.rb +121 -0
- data/lib/fhcap/version.rb +3 -0
- data/spec/fhcap/cli_spec.rb +6 -0
- data/spec/fhcap/tasks/cluster/create_spec.rb +46 -0
- data/spec/fhcap/tasks/knife/add_spec.rb +35 -0
- data/spec/fhcap/tasks/knife/remove_spec.rb +25 -0
- data/spec/fhcap/tasks/provider/add_spec.rb +61 -0
- data/spec/fhcap/tasks/provider/remove_spec.rb +25 -0
- data/spec/fhcap/tasks/repo/add_spec.rb +32 -0
- data/spec/fhcap/tasks/repo/remove_spec.rb +25 -0
- data/spec/fhcap/tasks/task_base_spec.rb +51 -0
- data/spec/fhcap/thor_base_spec.rb +9 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/support/dummy_config.rb +7 -0
- data/spec/support/dummy_thor.rb +3 -0
- data/templates/chef/cookbook/changelog.md.erb +12 -0
- data/templates/chef/cookbook/metadata.erb +45 -0
- data/templates/chef/environment_core.json.erb +278 -0
- data/templates/chef/environment_empty.json.erb +10 -0
- data/templates/chef/environment_mbaas.json.erb +120 -0
- data/templates/chef/environment_single.json.erb +300 -0
- data/templates/cluster/aws/common.json.erb +43 -0
- data/templates/cluster/aws/core-3node.json.erb +106 -0
- data/templates/cluster/aws/core-small-9node.json.erb +333 -0
- data/templates/cluster/aws/mbaas-3node.json.erb +116 -0
- data/templates/cluster/aws/nginx-test.json.erb +93 -0
- data/templates/cluster/aws/single-blank.json.erb +41 -0
- data/templates/cluster/aws/single.json.erb +88 -0
- data/templates/cluster/core-3node.json.erb +8 -0
- data/templates/cluster/core-mbaas-6node.json.erb +13 -0
- data/templates/cluster/core-small-9node.json.erb +8 -0
- data/templates/cluster/mbaas-3node.json.erb +9 -0
- data/templates/cluster/nginx-test.json.erb +8 -0
- data/templates/cluster/openstack/common.json.erb +7 -0
- data/templates/cluster/openstack/core-3node.json.erb +14 -0
- data/templates/cluster/openstack/core-small-9node.json.erb +32 -0
- data/templates/cluster/openstack/mbaas-3node.json.erb +14 -0
- data/templates/cluster/openstack/nginx-test.json.erb +11 -0
- data/templates/cluster/openstack/single-blank.json.erb +10 -0
- data/templates/cluster/openstack/single.json.erb +10 -0
- data/templates/cluster/single-blank.json.erb +8 -0
- data/templates/cluster/single.json.erb +8 -0
- data/templates/init/knife.rb.erb +13 -0
- data/templates/kitchen/Cheffile.erb +11 -0
- data/templates/kitchen/kitchen.aws.yml.erb +35 -0
- data/templates/kitchen/kitchen.docker.yml.erb +24 -0
- data/templates/kitchen/kitchen.generate.yml.erb +2 -0
- data/templates/kitchen/kitchen.openstack.yml.erb +31 -0
- metadata +506 -0
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'fhcap/tasks/task_base'
|
2
|
+
require 'openssl'
|
3
|
+
|
4
|
+
module Fhcap
|
5
|
+
module Tasks
|
6
|
+
module Misc
|
7
|
+
class CreateSslCert < TaskBase
|
8
|
+
|
9
|
+
def initialize(options)
|
10
|
+
super
|
11
|
+
@domain = options[:domain]
|
12
|
+
@name = options[:name]
|
13
|
+
@directory = options[:directory]
|
14
|
+
@format = options[:format]
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
case @format
|
19
|
+
when 'pem'
|
20
|
+
certificate_file = File.join(@directory, "#{@name}-certificate.pem")
|
21
|
+
private_key_file = File.join(@directory, "#{@name}-private-key.pem")
|
22
|
+
if File.exists?(certificate_file) && File.exists?(private_key_file)
|
23
|
+
thor.say_status 'exists', certificate_file, :green
|
24
|
+
thor.say_status 'exists', private_key_file, :green
|
25
|
+
else
|
26
|
+
key, cert = generate_cert(@domain)
|
27
|
+
thor.create_file(private_key_file, key.to_pem)
|
28
|
+
thor.create_file(certificate_file, cert.to_pem)
|
29
|
+
end
|
30
|
+
when 'json'
|
31
|
+
certificate_file = File.join(@directory, "#{@name}.json")
|
32
|
+
|
33
|
+
if File.exists?(certificate_file)
|
34
|
+
thor.say_status 'exists', certificate_file, :green
|
35
|
+
else
|
36
|
+
key, cert = generate_cert(@domain)
|
37
|
+
cert_conf = {
|
38
|
+
id: @name,
|
39
|
+
cert: cert.to_pem.split(/\n/),
|
40
|
+
key: key.to_pem.split(/\n/)
|
41
|
+
}
|
42
|
+
thor.create_file(certificate_file, JSON.pretty_generate(cert_conf))
|
43
|
+
end
|
44
|
+
else
|
45
|
+
exit_with_error("Unsupported format #{@format}")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def generate_cert(domain)
|
52
|
+
#https://gist.github.com/nickyp/886884
|
53
|
+
key = OpenSSL::PKey::RSA.new(2048)
|
54
|
+
public_key = key.public_key
|
55
|
+
|
56
|
+
subject = "/C=BE/O=RH/OU=RH/CN=*.#{domain}"
|
57
|
+
|
58
|
+
cert = OpenSSL::X509::Certificate.new
|
59
|
+
cert.subject = cert.issuer = OpenSSL::X509::Name.parse(subject)
|
60
|
+
cert.not_before = Time.now
|
61
|
+
cert.not_after = Time.now + 365 * 24 * 60 * 60
|
62
|
+
cert.public_key = public_key
|
63
|
+
cert.serial = 0x0
|
64
|
+
cert.version = 2
|
65
|
+
|
66
|
+
ef = OpenSSL::X509::ExtensionFactory.new
|
67
|
+
ef.subject_certificate = cert
|
68
|
+
ef.issuer_certificate = cert
|
69
|
+
cert.extensions = [
|
70
|
+
ef.create_extension("basicConstraints","CA:TRUE", true),
|
71
|
+
ef.create_extension("subjectKeyIdentifier", "hash")
|
72
|
+
]
|
73
|
+
cert.add_extension ef.create_extension("authorityKeyIdentifier",
|
74
|
+
"keyid:always,issuer:always")
|
75
|
+
cert.sign key, OpenSSL::Digest::SHA256.new
|
76
|
+
[key, cert]
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'fhcap/tasks/task_base'
|
2
|
+
require 'aws-sdk'
|
3
|
+
|
4
|
+
module Fhcap
|
5
|
+
module Tasks
|
6
|
+
module Provider
|
7
|
+
class Add < TaskBase
|
8
|
+
|
9
|
+
attr_reader :name, :credentials, :type
|
10
|
+
|
11
|
+
AWS_REQUIRED_CREDENTIALS = %w{aws-access-key aws-secret-key}
|
12
|
+
OS_REQUIRED_CREDENTIALS = %w{os-auth-url os-tenant-id os-tenant-name os-username os-password}
|
13
|
+
|
14
|
+
def initialize(options)
|
15
|
+
super
|
16
|
+
@name = options[:name]
|
17
|
+
@type = options[:type]
|
18
|
+
@credentials = options[:credentials] || {}
|
19
|
+
if options[:type] == 'aws'
|
20
|
+
@required_credentials = AWS_REQUIRED_CREDENTIALS
|
21
|
+
elsif options[:type] == 'openstack'
|
22
|
+
@required_credentials = OS_REQUIRED_CREDENTIALS
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def run
|
27
|
+
thor.say "Provider::Add: name = #{name}, type = #{type}", :yellow
|
28
|
+
|
29
|
+
config[:providers] = {} unless config[:providers]
|
30
|
+
config[:providers][type.to_sym] = {} unless config[:providers][type.to_sym]
|
31
|
+
config[:providers][type.to_sym][name.to_sym] = {} unless config[:providers][type.to_sym][name.to_sym]
|
32
|
+
|
33
|
+
@provider_config = config[:providers][type.to_sym][name.to_sym]
|
34
|
+
@provider_config[:provides] = [] unless @provider_config[:provides]
|
35
|
+
@provider_config[:credentials] = {} unless @provider_config[:credentials]
|
36
|
+
@provider_config[:credentials].merge!(credentials)
|
37
|
+
|
38
|
+
@required_credentials.each do |rc|
|
39
|
+
if !@provider_config[:credentials][rc.to_sym] || options[:interactive]
|
40
|
+
default = @provider_config[:credentials][rc.to_sym] || ENV[rc.to_s.upcase.gsub('-', '_')]
|
41
|
+
@provider_config[:credentials][rc.to_sym] = thor.ask "#{rc}:", {default: default}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
send(:"#{type}_config", @provider_config)
|
46
|
+
|
47
|
+
thor.create_file(config.default_config_file, JSON.pretty_generate(config.data), :force => true)
|
48
|
+
config.reload
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def openstack_config(cfg)
|
54
|
+
ask_config({
|
55
|
+
image_ref: {},
|
56
|
+
flavor_ref: {},
|
57
|
+
floating_ip_pool: {},
|
58
|
+
ssh_username: {}
|
59
|
+
}, cfg)
|
60
|
+
cfg[:provides] << 'compute'
|
61
|
+
end
|
62
|
+
|
63
|
+
def aws_config(cfg)
|
64
|
+
aws_compute(cfg)
|
65
|
+
aws_dns(cfg)
|
66
|
+
end
|
67
|
+
|
68
|
+
def aws_compute(cfg)
|
69
|
+
creds = cfg[:credentials]
|
70
|
+
cfg[:regions] = {}
|
71
|
+
ec2 = Aws::EC2::Client.new(
|
72
|
+
region: 'eu-west-1',
|
73
|
+
access_key_id: creds[:'aws-access-key'],
|
74
|
+
secret_access_key: creds[:'aws-secret-key']
|
75
|
+
)
|
76
|
+
|
77
|
+
resp = ec2.describe_regions
|
78
|
+
thor.say "Found #{resp.regions.length} regions for this AWS account: #{resp.regions.collect{|r|r.region_name}}"
|
79
|
+
resp.regions.each do |region|
|
80
|
+
thor.say "Configure #{region.region_name}", :yellow
|
81
|
+
ec2 = Aws::EC2::Client.new(
|
82
|
+
region: region.region_name,
|
83
|
+
access_key_id: creds[:'aws-access-key'],
|
84
|
+
secret_access_key: creds[:'aws-secret-key']
|
85
|
+
)
|
86
|
+
|
87
|
+
resp = ec2.describe_images({
|
88
|
+
filters: [
|
89
|
+
{
|
90
|
+
name: "tag:fhcap-base",
|
91
|
+
values: ["true"],
|
92
|
+
},
|
93
|
+
],
|
94
|
+
})
|
95
|
+
if resp.images.empty?
|
96
|
+
thor.say "Could not determine valid base image, tag an appropriate image with \"fhcap-base:true\", and re-run this command to add this region!"
|
97
|
+
next
|
98
|
+
end
|
99
|
+
cfg[:regions][region.region_name.to_sym] = {}
|
100
|
+
|
101
|
+
base_image = resp.images.first.image_id
|
102
|
+
thor.say "Adding Base Image: #{base_image}"
|
103
|
+
cfg[:regions][region.region_name.to_sym][:base_image] = base_image
|
104
|
+
|
105
|
+
resp = ec2.describe_availability_zones
|
106
|
+
zones = resp.availability_zones.collect do |az|
|
107
|
+
az.zone_name
|
108
|
+
end
|
109
|
+
thor.say "Adding #{zones.length} Availability Zones: #{zones}"
|
110
|
+
cfg[:regions][region.region_name.to_sym][:availability_zones] = zones
|
111
|
+
|
112
|
+
end
|
113
|
+
cfg[:provides] << 'compute'
|
114
|
+
cfg[:provides].uniq!
|
115
|
+
end
|
116
|
+
|
117
|
+
def aws_dns(cfg)
|
118
|
+
creds = cfg[:credentials]
|
119
|
+
client = Aws::Route53::Client.new(
|
120
|
+
region: 'eu-west-1',
|
121
|
+
access_key_id: creds[:'aws-access-key'],
|
122
|
+
secret_access_key: creds[:'aws-secret-key']
|
123
|
+
)
|
124
|
+
resp = client.list_hosted_zones
|
125
|
+
|
126
|
+
domains = resp.hosted_zones.map {|z|z.name.gsub(/\.$/, '')}
|
127
|
+
thor.say "Adding Domains: #{domains}"
|
128
|
+
cfg[:domains] = domains
|
129
|
+
cfg[:provides] << 'dns'
|
130
|
+
cfg[:provides].uniq!
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'fhcap/tasks/task_base'
|
2
|
+
|
3
|
+
module Fhcap
|
4
|
+
module Tasks
|
5
|
+
module Provider
|
6
|
+
class List < TaskBase
|
7
|
+
|
8
|
+
def run
|
9
|
+
thor.say "Provider::List", :yellow
|
10
|
+
|
11
|
+
table_contents = [table_header('ID', 'Provides', 'Regions', 'Credentials')]
|
12
|
+
|
13
|
+
providers_config.each do |type, type_cfg|
|
14
|
+
type_cfg.each do |provider_id, provider_cfg|
|
15
|
+
regions = (provider_cfg[:regions] ? provider_cfg[:regions].keys : []).join(',')
|
16
|
+
provides = (provider_cfg[:provides] ? provider_cfg[:provides] : []).join(',')
|
17
|
+
credentials = provider_cfg[:credentials].each do |k,v|
|
18
|
+
if k.to_s =~ /password|secret/
|
19
|
+
provider_cfg[:credentials][k] = '*' * v.length
|
20
|
+
end
|
21
|
+
end
|
22
|
+
table_contents << table_row("#{type}:#{provider_id}", provides, regions, credentials)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
thor.print_table table_contents
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'fhcap/tasks/task_base'
|
2
|
+
|
3
|
+
module Fhcap
|
4
|
+
module Tasks
|
5
|
+
module Provider
|
6
|
+
class Remove < TaskBase
|
7
|
+
|
8
|
+
attr_reader :name, :type
|
9
|
+
|
10
|
+
def initialize(options)
|
11
|
+
super
|
12
|
+
@name = options[:name]
|
13
|
+
@type = options[:type]
|
14
|
+
end
|
15
|
+
|
16
|
+
def run
|
17
|
+
thor.say "Provider::Remove: name = #{name}", :yellow
|
18
|
+
if thor.yes? "Remove provider #{name}? (y/n)"
|
19
|
+
config[:providers][type.to_sym].delete(name.to_sym)
|
20
|
+
thor.create_file(config.default_config_file, JSON.pretty_generate(config.data), :force => true)
|
21
|
+
config.reload
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'fhcap/tasks/task_base'
|
2
|
+
require 'fhcap/tasks/repo/checkout'
|
3
|
+
require 'fhcap/tasks/setup'
|
4
|
+
|
5
|
+
module Fhcap
|
6
|
+
module Tasks
|
7
|
+
module Repo
|
8
|
+
class Add < TaskBase
|
9
|
+
|
10
|
+
attr_reader :name, :repo_config
|
11
|
+
|
12
|
+
def initialize(options)
|
13
|
+
super
|
14
|
+
@name = options[:name]
|
15
|
+
|
16
|
+
@repo_config = config[:repos][@name.to_sym] || {}
|
17
|
+
@repo_config = {
|
18
|
+
url: options[:url],
|
19
|
+
clusters_dir: options[:'clusters-dir'] || 'clusters',
|
20
|
+
}.merge(@repo_config)
|
21
|
+
|
22
|
+
@skip_setup = options[:'skip-setup']
|
23
|
+
end
|
24
|
+
|
25
|
+
def run
|
26
|
+
thor.say "Repo::Add: name = #{name}", :yellow
|
27
|
+
|
28
|
+
ask_config(required_config, repo_config)
|
29
|
+
|
30
|
+
if repo_config[:url] =~ /fhcap.git$/
|
31
|
+
repo_config[:archives] = {
|
32
|
+
cookbooks: config.fhcap_cookbook_archive_url
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
config[:repos][name.to_sym] = repo_config
|
37
|
+
thor.create_file(config.default_config_file, JSON.pretty_generate(config.data), :force => true)
|
38
|
+
config.reload
|
39
|
+
Checkout.new(@options.dup.merge({:repo => name, :'git-ref' => 'master'})).run
|
40
|
+
Tasks::Setup.new(@options).run unless @skip_setup
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def required_config
|
46
|
+
{
|
47
|
+
url: {
|
48
|
+
},
|
49
|
+
clusters_dir: {
|
50
|
+
}
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'fhcap/tasks/task_base'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module Fhcap
|
6
|
+
module Tasks
|
7
|
+
module Repo
|
8
|
+
class Checkout < TaskBase
|
9
|
+
|
10
|
+
attr_reader :gitref, :repo, :fallback_gitref, :remote
|
11
|
+
|
12
|
+
def initialize(options)
|
13
|
+
super
|
14
|
+
@gitref = options[:"git-ref"]
|
15
|
+
@repo = options[:repo] || options[:name]
|
16
|
+
@fallback_gitref = options[:'fallback-git-ref']
|
17
|
+
@remote = options[:remote] || options[:'git-remote'] || 'origin'
|
18
|
+
end
|
19
|
+
|
20
|
+
def run
|
21
|
+
thor.say "Repo::Checkout: repo = #{repo}, git-ref = #{gitref}, remote = #{remote}\n", :yellow
|
22
|
+
if git_clone(repo)
|
23
|
+
if gitref
|
24
|
+
if clean?(repo)
|
25
|
+
unless checkout_git_ref
|
26
|
+
exit_with_error("Failed to checkout #{gitref} on #{repo} repo!")
|
27
|
+
end
|
28
|
+
else
|
29
|
+
exit_with_error("You specified a git-ref option, but have uncommitted changes in your local repo (#{repo_dir(repo)}). Please commit your local changes before continuing!")
|
30
|
+
end
|
31
|
+
else
|
32
|
+
current_ref = Dir.chdir repo_dir(repo) do
|
33
|
+
options[:verbose] ? `git rev-list HEAD -n 1 --pretty` : `git rev-parse HEAD`
|
34
|
+
end
|
35
|
+
thor.say "No git-ref option specified, using current ref: #{current_ref}"
|
36
|
+
end
|
37
|
+
else
|
38
|
+
exit_with_error("Failed to clone #{repo}!")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def git_clone(repo)
|
45
|
+
Dir.exists?(repo_dir(repo)) ? true : do_clone_cmd(repo)
|
46
|
+
end
|
47
|
+
|
48
|
+
def do_clone_cmd(repo)
|
49
|
+
cmd = %w{git clone}
|
50
|
+
cmd << '--quiet' unless verbose
|
51
|
+
cmd << repo_cfg(repo)[:url]
|
52
|
+
cmd << repo
|
53
|
+
cmd = cmd.join(' ')
|
54
|
+
status = -1
|
55
|
+
thor.inside(repos_dir) do
|
56
|
+
thor.run(cmd, :capture => !verbose)
|
57
|
+
status = $?.exitstatus
|
58
|
+
end
|
59
|
+
status == 0
|
60
|
+
end
|
61
|
+
|
62
|
+
def git_checkout_deploy(repo)
|
63
|
+
cmd = %w{git checkout -B deploy}
|
64
|
+
cmd << '--quiet' unless verbose
|
65
|
+
cmd = cmd.join(' ')
|
66
|
+
run_inside_repo_dir(repo_dir(repo), cmd)
|
67
|
+
end
|
68
|
+
|
69
|
+
def git_reset(repo)
|
70
|
+
result = do_reset_cmd(repo, gitref)
|
71
|
+
unless result == true
|
72
|
+
if fallback_gitref
|
73
|
+
thor.say "Unable to checkout #{gitref} on #{repo}, falling back to #{fallback_gitref}"
|
74
|
+
result = do_reset_cmd(repo, fallback_gitref)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
result
|
78
|
+
end
|
79
|
+
|
80
|
+
def do_fetch_cmd(repo, gitref)
|
81
|
+
cmd = %w{git fetch}
|
82
|
+
cmd << remote
|
83
|
+
cmd << gitref
|
84
|
+
cmd << '--quiet' unless verbose
|
85
|
+
cmd = cmd.join(' ')
|
86
|
+
run_inside_repo_dir(repo_dir(repo), cmd)
|
87
|
+
end
|
88
|
+
|
89
|
+
def do_reset_cmd(repo, gitref)
|
90
|
+
if do_fetch_cmd(repo, gitref)
|
91
|
+
cmd = %w{git reset --hard FETCH_HEAD}
|
92
|
+
cmd << '--quiet' unless verbose
|
93
|
+
cmd = cmd.join(' ')
|
94
|
+
run_inside_repo_dir(repo_dir(repo), cmd)
|
95
|
+
else
|
96
|
+
false
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def repo_post_checkout(repo)
|
101
|
+
repo_cfg = repo_cfg(repo)
|
102
|
+
repo_dir = repo_dir(repo)
|
103
|
+
repo_extract_archives(repo_dir, repo_cfg)
|
104
|
+
repo_librarian_install(repo_dir)
|
105
|
+
end
|
106
|
+
|
107
|
+
def repo_extract_archives(repo_dir, repo_cfg)
|
108
|
+
if repo_cfg && repo_cfg[:archives]
|
109
|
+
repo_cfg[:archives].each do |dir, url|
|
110
|
+
dir = dir.to_s
|
111
|
+
url = url.to_s
|
112
|
+
uri = URI.parse(url)
|
113
|
+
filename = File.join(Dir.tmpdir, File.basename(uri.path))
|
114
|
+
open(filename, 'wb') do |file|
|
115
|
+
file << open(url).read
|
116
|
+
end
|
117
|
+
cmd = "tar xf #{filename} -C #{repo_dir}"
|
118
|
+
run_inside_repo_dir(repo_dir, cmd)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def repo_librarian_install(repo_dir)
|
124
|
+
if File.exists? File.join(repo_dir, 'Cheffile')
|
125
|
+
cmd = %w{librarian-chef install}
|
126
|
+
cmd << '--quiet' unless verbose
|
127
|
+
cmd = cmd.join(' ')
|
128
|
+
run_inside_repo_dir(repo_dir, cmd)
|
129
|
+
end
|
130
|
+
true
|
131
|
+
end
|
132
|
+
|
133
|
+
def clean?(repo)
|
134
|
+
!modified?(repo_dir(repo), 'HEAD')
|
135
|
+
end
|
136
|
+
|
137
|
+
def checkout_git_ref
|
138
|
+
clean?(repo) && git_checkout_deploy(repo) && git_reset(repo) && repo_post_checkout(repo)
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|