fhcap-cli 0.3.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.
Files changed (142) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rakeTasks +7 -0
  4. data/.rspec +1 -0
  5. data/CHANGELOG.md +15 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +150 -0
  9. data/Rakefile +2 -0
  10. data/bin/fhcap +6 -0
  11. data/fhcap-cli.gemspec +44 -0
  12. data/lib/cookbooks/provision/libraries/provision.rb +140 -0
  13. data/lib/cookbooks/provision/metadata.rb +7 -0
  14. data/lib/cookbooks/provision/recipes/aws.rb +15 -0
  15. data/lib/cookbooks/provision/recipes/aws_cluster_create.rb +59 -0
  16. data/lib/cookbooks/provision/recipes/aws_cluster_create_elb.rb +61 -0
  17. data/lib/cookbooks/provision/recipes/aws_cluster_destroy.rb +52 -0
  18. data/lib/cookbooks/provision/recipes/cluster_create.rb +2 -0
  19. data/lib/cookbooks/provision/recipes/cluster_destroy.rb +2 -0
  20. data/lib/cookbooks/provision/recipes/cluster_destroy_instances.rb +11 -0
  21. data/lib/cookbooks/provision/recipes/cluster_provision.rb +4 -0
  22. data/lib/cookbooks/provision/recipes/cluster_provision_instances.rb +55 -0
  23. data/lib/cookbooks/provision/recipes/cluster_status.rb +24 -0
  24. data/lib/cookbooks/provision/recipes/common.rb +9 -0
  25. data/lib/cookbooks/provision/recipes/default.rb +5 -0
  26. data/lib/cookbooks/provision/recipes/openstack.rb +11 -0
  27. data/lib/cookbooks/provision/recipes/openstack_cluster_create.rb +11 -0
  28. data/lib/cookbooks/provision/recipes/openstack_cluster_destroy.rb +4 -0
  29. data/lib/cookbooks/provision/recipes/reset_rabbitmq.rb +49 -0
  30. data/lib/cookbooks/provision/recipes/restart_services.rb +24 -0
  31. data/lib/extensions/chef/provisioning.rb +21 -0
  32. data/lib/extensions/chef/provisioning/aws_driver/driver.rb +46 -0
  33. data/lib/extensions/chef/provisioning/chef_run_data.rb +18 -0
  34. data/lib/extensions/cheffish/merged_config.rb +9 -0
  35. data/lib/fhcap.rb +14 -0
  36. data/lib/fhcap/chef-dk/chef_runner.rb +94 -0
  37. data/lib/fhcap/cli.rb +75 -0
  38. data/lib/fhcap/cluster.rb +112 -0
  39. data/lib/fhcap/config.rb +104 -0
  40. data/lib/fhcap/cookbook.rb +75 -0
  41. data/lib/fhcap/dummy_node.rb +80 -0
  42. data/lib/fhcap/fhcap_helper.rb +9 -0
  43. data/lib/fhcap/kitchen.rb +235 -0
  44. data/lib/fhcap/knife.rb +74 -0
  45. data/lib/fhcap/knife_helper.rb +38 -0
  46. data/lib/fhcap/misc.rb +103 -0
  47. data/lib/fhcap/provider.rb +41 -0
  48. data/lib/fhcap/providers_helper.rb +60 -0
  49. data/lib/fhcap/repo.rb +52 -0
  50. data/lib/fhcap/repos_helper.rb +217 -0
  51. data/lib/fhcap/tasks/chef/chef_task_base.rb +82 -0
  52. data/lib/fhcap/tasks/chef/cookbook/list.rb +37 -0
  53. data/lib/fhcap/tasks/chef/cookbook/update_changelog.rb +63 -0
  54. data/lib/fhcap/tasks/chef/cookbook/update_metadata.rb +57 -0
  55. data/lib/fhcap/tasks/chef/cookbook/update_readme.rb +30 -0
  56. data/lib/fhcap/tasks/chef/cookbook/update_version.rb +90 -0
  57. data/lib/fhcap/tasks/chef/environments/create.rb +115 -0
  58. data/lib/fhcap/tasks/chef/environments/destroy.rb +37 -0
  59. data/lib/fhcap/tasks/chef/environments/promote_cookbooks.rb +47 -0
  60. data/lib/fhcap/tasks/chef/provisioning/chef_provisioning_task.rb +27 -0
  61. data/lib/fhcap/tasks/chef/provisioning/chef_provisioning_task_base.rb +38 -0
  62. data/lib/fhcap/tasks/chef/provisioning/create.rb +22 -0
  63. data/lib/fhcap/tasks/chef/provisioning/destroy.rb +21 -0
  64. data/lib/fhcap/tasks/chef/provisioning/provision.rb +19 -0
  65. data/lib/fhcap/tasks/chef/server/bootstrap.rb +165 -0
  66. data/lib/fhcap/tasks/chef/server/create_user.rb +97 -0
  67. data/lib/fhcap/tasks/chef/server/info.rb +82 -0
  68. data/lib/fhcap/tasks/chef/server/provision.rb +45 -0
  69. data/lib/fhcap/tasks/clean.rb +34 -0
  70. data/lib/fhcap/tasks/cluster/cluster_task_base.rb +57 -0
  71. data/lib/fhcap/tasks/cluster/create.rb +243 -0
  72. data/lib/fhcap/tasks/cluster/create_environment.rb +171 -0
  73. data/lib/fhcap/tasks/cluster/destroy.rb +30 -0
  74. data/lib/fhcap/tasks/cluster/destroy_environment.rb +28 -0
  75. data/lib/fhcap/tasks/cluster/info.rb +67 -0
  76. data/lib/fhcap/tasks/cluster/list.rb +40 -0
  77. data/lib/fhcap/tasks/cluster/provision.rb +46 -0
  78. data/lib/fhcap/tasks/cluster/status.rb +17 -0
  79. data/lib/fhcap/tasks/cluster/test.rb +15 -0
  80. data/lib/fhcap/tasks/knife/add.rb +111 -0
  81. data/lib/fhcap/tasks/knife/list.rb +22 -0
  82. data/lib/fhcap/tasks/knife/remove.rb +39 -0
  83. data/lib/fhcap/tasks/misc/create_dns_record.rb +100 -0
  84. data/lib/fhcap/tasks/misc/create_ssl_cert.rb +82 -0
  85. data/lib/fhcap/tasks/provider/add.rb +136 -0
  86. data/lib/fhcap/tasks/provider/list.rb +31 -0
  87. data/lib/fhcap/tasks/provider/remove.rb +28 -0
  88. data/lib/fhcap/tasks/repo/add.rb +57 -0
  89. data/lib/fhcap/tasks/repo/checkout.rb +144 -0
  90. data/lib/fhcap/tasks/repo/list.rb +22 -0
  91. data/lib/fhcap/tasks/repo/remove.rb +34 -0
  92. data/lib/fhcap/tasks/setup.rb +59 -0
  93. data/lib/fhcap/tasks/task_base.rb +89 -0
  94. data/lib/fhcap/thor_base.rb +121 -0
  95. data/lib/fhcap/version.rb +3 -0
  96. data/spec/fhcap/cli_spec.rb +6 -0
  97. data/spec/fhcap/tasks/cluster/create_spec.rb +46 -0
  98. data/spec/fhcap/tasks/knife/add_spec.rb +35 -0
  99. data/spec/fhcap/tasks/knife/remove_spec.rb +25 -0
  100. data/spec/fhcap/tasks/provider/add_spec.rb +61 -0
  101. data/spec/fhcap/tasks/provider/remove_spec.rb +25 -0
  102. data/spec/fhcap/tasks/repo/add_spec.rb +32 -0
  103. data/spec/fhcap/tasks/repo/remove_spec.rb +25 -0
  104. data/spec/fhcap/tasks/task_base_spec.rb +51 -0
  105. data/spec/fhcap/thor_base_spec.rb +9 -0
  106. data/spec/spec_helper.rb +23 -0
  107. data/spec/support/dummy_config.rb +7 -0
  108. data/spec/support/dummy_thor.rb +3 -0
  109. data/templates/chef/cookbook/changelog.md.erb +12 -0
  110. data/templates/chef/cookbook/metadata.erb +45 -0
  111. data/templates/chef/environment_core.json.erb +278 -0
  112. data/templates/chef/environment_empty.json.erb +10 -0
  113. data/templates/chef/environment_mbaas.json.erb +120 -0
  114. data/templates/chef/environment_single.json.erb +300 -0
  115. data/templates/cluster/aws/common.json.erb +43 -0
  116. data/templates/cluster/aws/core-3node.json.erb +106 -0
  117. data/templates/cluster/aws/core-small-9node.json.erb +333 -0
  118. data/templates/cluster/aws/mbaas-3node.json.erb +116 -0
  119. data/templates/cluster/aws/nginx-test.json.erb +93 -0
  120. data/templates/cluster/aws/single-blank.json.erb +41 -0
  121. data/templates/cluster/aws/single.json.erb +88 -0
  122. data/templates/cluster/core-3node.json.erb +8 -0
  123. data/templates/cluster/core-mbaas-6node.json.erb +13 -0
  124. data/templates/cluster/core-small-9node.json.erb +8 -0
  125. data/templates/cluster/mbaas-3node.json.erb +9 -0
  126. data/templates/cluster/nginx-test.json.erb +8 -0
  127. data/templates/cluster/openstack/common.json.erb +7 -0
  128. data/templates/cluster/openstack/core-3node.json.erb +14 -0
  129. data/templates/cluster/openstack/core-small-9node.json.erb +32 -0
  130. data/templates/cluster/openstack/mbaas-3node.json.erb +14 -0
  131. data/templates/cluster/openstack/nginx-test.json.erb +11 -0
  132. data/templates/cluster/openstack/single-blank.json.erb +10 -0
  133. data/templates/cluster/openstack/single.json.erb +10 -0
  134. data/templates/cluster/single-blank.json.erb +8 -0
  135. data/templates/cluster/single.json.erb +8 -0
  136. data/templates/init/knife.rb.erb +13 -0
  137. data/templates/kitchen/Cheffile.erb +11 -0
  138. data/templates/kitchen/kitchen.aws.yml.erb +35 -0
  139. data/templates/kitchen/kitchen.docker.yml.erb +24 -0
  140. data/templates/kitchen/kitchen.generate.yml.erb +2 -0
  141. data/templates/kitchen/kitchen.openstack.yml.erb +31 -0
  142. 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