cucumber-chef 2.0.7 → 2.1.0.rc.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.
- data/README.md +1 -1
- data/Rakefile +1 -1
- data/bin/cc-knife +2 -5
- data/bin/cc-push +50 -26
- data/bin/cc-server +9 -10
- data/bin/cucumber-chef +65 -71
- data/chef_repo/cookbooks/cucumber-chef/attributes/default.rb +1 -1
- data/chef_repo/cookbooks/cucumber-chef/recipes/default.rb +1 -1
- data/chef_repo/cookbooks/cucumber-chef/recipes/lxc.rb +34 -36
- data/chef_repo/cookbooks/cucumber-chef/recipes/test_lab.rb +64 -47
- data/chef_repo/cookbooks/cucumber-chef/templates/default/solrconfig.erb +650 -0
- data/cucumber-chef.gemspec +5 -5
- data/lib/cucumber/chef/bootstrap.rb +10 -10
- data/lib/cucumber/chef/config.rb +15 -15
- data/lib/cucumber/chef/helpers/chef_client.rb +88 -14
- data/lib/cucumber/chef/helpers/chef_server.rb +39 -16
- data/lib/cucumber/chef/helpers/command.rb +28 -12
- data/lib/cucumber/chef/helpers/container.rb +29 -26
- data/lib/cucumber/chef/helpers/minitest.rb +1 -1
- data/lib/cucumber/chef/helpers/server.rb +37 -18
- data/lib/cucumber/chef/helpers/test_lab.rb +1 -1
- data/lib/cucumber/chef/helpers/utility.rb +23 -3
- data/lib/cucumber/chef/helpers.rb +10 -8
- data/lib/cucumber/chef/provisioner.rb +22 -21
- data/lib/cucumber/chef/steps/chef_steps.rb +1 -1
- data/lib/cucumber/chef/steps/minitest_steps.rb +3 -3
- data/lib/cucumber/chef/steps/provision_steps.rb +7 -6
- data/lib/cucumber/chef/steps/ssh_steps.rb +31 -2
- data/lib/cucumber/chef/steps.rb +1 -1
- data/lib/cucumber/chef/templates/cucumber/cc-hooks.rb +111 -0
- data/lib/cucumber/chef/templates/cucumber/env.rb +0 -87
- data/lib/cucumber/chef/templates/cucumber/readme-environments.erb +1 -0
- data/lib/cucumber/chef/templates/cucumber/readme-roles.erb +1 -1
- data/lib/cucumber/chef/templates/cucumber-chef/config-rb.erb +5 -0
- data/lib/cucumber/chef/test_lab.rb +70 -23
- data/lib/cucumber/chef/utility.rb +121 -31
- data/lib/cucumber/chef/version.rb +2 -2
- data/lib/cucumber/chef.rb +1 -1
- data/lib/cucumber-chef.rb +1 -1
- data/spec/cucumber/chef/config_spec.rb +1 -1
- data/spec/cucumber/chef/provisioner_spec.rb +1 -1
- data/spec/cucumber/chef/test_lab_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- metadata +8 -5
| @@ -2,7 +2,7 @@ | |
| 2 2 | 
             
            #
         | 
| 3 3 | 
             
            #      Author: Stephen Nelson-Smith <stephen@atalanta-systems.com>
         | 
| 4 4 | 
             
            #      Author: Zachary Patten <zachary@jovelabs.com>
         | 
| 5 | 
            -
            #   Copyright: Copyright (c) 2011- | 
| 5 | 
            +
            #   Copyright: Copyright (c) 2011-2013 Atalanta Systems Ltd
         | 
| 6 6 | 
             
            #     License: Apache License, Version 2.0
         | 
| 7 7 | 
             
            #
         | 
| 8 8 | 
             
            #   Licensed under the Apache License, Version 2.0 (the "License");
         | 
| @@ -41,33 +41,33 @@ module Cucumber | |
| 41 41 | 
             
            ################################################################################
         | 
| 42 42 |  | 
| 43 43 | 
             
                  def run
         | 
| 44 | 
            -
                     | 
| 44 | 
            +
                    Cucumber::Chef.logger.debug { "config(#{@config.inspect})" }
         | 
| 45 45 |  | 
| 46 46 | 
             
                    if !@config[:template_file]
         | 
| 47 47 | 
             
                      message = "You must supply a 'template_file' option."
         | 
| 48 | 
            -
                       | 
| 48 | 
            +
                      Cucumber::Chef.logger.fatal { message }
         | 
| 49 49 | 
             
                      raise BootstrapError, message
         | 
| 50 50 | 
             
                    end
         | 
| 51 51 |  | 
| 52 52 | 
             
                    if !@config[:host]
         | 
| 53 53 | 
             
                      message = "You must supply a 'host' option."
         | 
| 54 | 
            -
                       | 
| 54 | 
            +
                      Cucumber::Chef.logger.fatal { message }
         | 
| 55 55 | 
             
                      raise BootstrapError, message
         | 
| 56 56 | 
             
                    end
         | 
| 57 57 |  | 
| 58 58 | 
             
                    if !@config[:ssh_user]
         | 
| 59 59 | 
             
                      message = "You must supply a 'ssh_user' option."
         | 
| 60 | 
            -
                       | 
| 60 | 
            +
                      Cucumber::Chef.logger.fatal { message }
         | 
| 61 61 | 
             
                      raise BootstrapError, message
         | 
| 62 62 | 
             
                    end
         | 
| 63 63 |  | 
| 64 64 | 
             
                    if (!@config[:ssh_password] && !@config[:identity_file])
         | 
| 65 65 | 
             
                      message = "You must supply a 'ssh_password' or 'identity_file' option."
         | 
| 66 | 
            -
                       | 
| 66 | 
            +
                      Cucumber::Chef.logger.fatal { message }
         | 
| 67 67 | 
             
                      raise BootstrapError, message
         | 
| 68 68 | 
             
                    end
         | 
| 69 69 |  | 
| 70 | 
            -
                     | 
| 70 | 
            +
                    Cucumber::Chef.logger.debug { "prepare(#{@config[:host]})" }
         | 
| 71 71 |  | 
| 72 72 | 
             
                    @ssh.config.host_name = @config[:host]
         | 
| 73 73 | 
             
                    @ssh.config.user = @config[:ssh_user]
         | 
| @@ -75,13 +75,13 @@ module Cucumber | |
| 75 75 | 
             
                    @ssh.config.keys = @config[:identity_file]
         | 
| 76 76 | 
             
                    @ssh.config.timeout = 5
         | 
| 77 77 |  | 
| 78 | 
            -
                     | 
| 78 | 
            +
                    Cucumber::Chef.logger.debug { "template_file(#{@config[:template_file]})" }
         | 
| 79 79 | 
             
                    command = ZTK::Template.render(@config[:template_file], @config[:context])
         | 
| 80 80 | 
             
                    command = "sudo #{command}" if @config[:use_sudo]
         | 
| 81 81 |  | 
| 82 | 
            -
                     | 
| 82 | 
            +
                    Cucumber::Chef.logger.debug { "begin(#{@config[:host]})" }
         | 
| 83 83 | 
             
                    @ssh.exec(command, :silence => true)
         | 
| 84 | 
            -
                     | 
| 84 | 
            +
                    Cucumber::Chef.logger.debug { "end(#{@config[:host]})" }
         | 
| 85 85 | 
             
                  end
         | 
| 86 86 |  | 
| 87 87 | 
             
            ################################################################################
         | 
    
        data/lib/cucumber/chef/config.rb
    CHANGED
    
    | @@ -2,7 +2,7 @@ | |
| 2 2 | 
             
            #
         | 
| 3 3 | 
             
            #      Author: Stephen Nelson-Smith <stephen@atalanta-systems.com>
         | 
| 4 4 | 
             
            #      Author: Zachary Patten <zachary@jovelabs.com>
         | 
| 5 | 
            -
            #   Copyright: Copyright (c) 2011- | 
| 5 | 
            +
            #   Copyright: Copyright (c) 2011-2013 Atalanta Systems Ltd
         | 
| 6 6 | 
             
            #     License: Apache License, Version 2.0
         | 
| 7 7 | 
             
            #
         | 
| 8 8 | 
             
            #   Licensed under the Apache License, Version 2.0 (the "License");
         | 
| @@ -51,14 +51,14 @@ module Cucumber | |
| 51 51 |  | 
| 52 52 | 
             
                  def self.load
         | 
| 53 53 | 
             
                    config_rb = Cucumber::Chef.locate(:file, ".cucumber-chef", "config.rb")
         | 
| 54 | 
            -
                     | 
| 54 | 
            +
                    Cucumber::Chef.logger.debug { "Attempting to load cucumber-chef configuration from '%s'." % config_rb }
         | 
| 55 55 | 
             
                    self.from_file(config_rb)
         | 
| 56 56 | 
             
                    self.verify
         | 
| 57 | 
            -
                     | 
| 57 | 
            +
                    Cucumber::Chef.logger.debug { "Successfully loaded cucumber-chef configuration from '%s'." % config_rb }
         | 
| 58 58 |  | 
| 59 59 | 
             
                    log_dump = self.duplicate(self.configuration)
         | 
| 60 60 | 
             
                    log_dump[:aws].merge!(:aws_access_key_id => "[REDACTED]", :aws_secret_access_key => "[REDACTED]")
         | 
| 61 | 
            -
                     | 
| 61 | 
            +
                    Cucumber::Chef.logger.debug { log_dump.inspect }
         | 
| 62 62 |  | 
| 63 63 | 
             
                    self
         | 
| 64 64 | 
             
                  rescue Errno::ENOENT, UtilityError
         | 
| @@ -77,25 +77,25 @@ module Cucumber | |
| 77 77 | 
             
                    self.verify_keys
         | 
| 78 78 | 
             
                    self.verify_provider_keys
         | 
| 79 79 | 
             
                    eval("self.verify_provider_#{self[:provider].to_s.downcase}")
         | 
| 80 | 
            -
                     | 
| 80 | 
            +
                    Cucumber::Chef.logger.debug { "Configuration verified successfully" }
         | 
| 81 81 | 
             
                  end
         | 
| 82 82 |  | 
| 83 83 | 
             
            ################################################################################
         | 
| 84 84 |  | 
| 85 85 | 
             
                  def self.verify_keys
         | 
| 86 | 
            -
                     | 
| 86 | 
            +
                    Cucumber::Chef.logger.debug { "Checking for missing configuration keys" }
         | 
| 87 87 | 
             
                    missing_keys = KEYS.select{ |key| !self[key.to_sym] }
         | 
| 88 88 | 
             
                    if missing_keys.count > 0
         | 
| 89 89 | 
             
                      message = "Configuration incomplete, missing configuration keys: #{missing_keys.join(", ")}"
         | 
| 90 | 
            -
                       | 
| 90 | 
            +
                      Cucumber::Chef.logger.fatal { message }
         | 
| 91 91 | 
             
                      raise ConfigError, message
         | 
| 92 92 | 
             
                    end
         | 
| 93 93 |  | 
| 94 | 
            -
                     | 
| 94 | 
            +
                    Cucumber::Chef.logger.debug { "Checking for invalid configuration keys" }
         | 
| 95 95 | 
             
                    invalid_keys = KEYS.select{ |key| !eval("#{key.to_s.upcase}S").include?(self[key]) }
         | 
| 96 96 | 
             
                    if invalid_keys.count > 0
         | 
| 97 97 | 
             
                      message = "Configuration incomplete, invalid configuration keys: #{invalid_keys.join(", ")}"
         | 
| 98 | 
            -
                       | 
| 98 | 
            +
                      Cucumber::Chef.logger.fatal { message }
         | 
| 99 99 | 
             
                      raise ConfigError, message
         | 
| 100 100 | 
             
                    end
         | 
| 101 101 | 
             
                  end
         | 
| @@ -103,11 +103,11 @@ module Cucumber | |
| 103 103 | 
             
            ################################################################################
         | 
| 104 104 |  | 
| 105 105 | 
             
                  def self.verify_provider_keys
         | 
| 106 | 
            -
                     | 
| 106 | 
            +
                    Cucumber::Chef.logger.debug { "Checking for missing provider keys" }
         | 
| 107 107 | 
             
                    missing_keys = eval("PROVIDER_#{self[:provider].to_s.upcase}_KEYS").select{ |key| !self[self[:provider]].key?(key) }
         | 
| 108 108 | 
             
                    if missing_keys.count > 0
         | 
| 109 109 | 
             
                      message = "Configuration incomplete, missing provider configuration keys: #{missing_keys.join(", ")}"
         | 
| 110 | 
            -
                       | 
| 110 | 
            +
                      Cucumber::Chef.logger.fatal { message }
         | 
| 111 111 | 
             
                      raise ConfigError, message
         | 
| 112 112 | 
             
                    end
         | 
| 113 113 | 
             
                  end
         | 
| @@ -122,14 +122,14 @@ module Cucumber | |
| 122 122 | 
             
                      compute.describe_availability_zones
         | 
| 123 123 | 
             
                    end
         | 
| 124 124 | 
             
                  rescue Fog::Service::Error => err
         | 
| 125 | 
            -
                    message = "Invalid AWS credentials.  Please check your configuration."
         | 
| 126 | 
            -
                     | 
| 125 | 
            +
                    message = "Invalid AWS credentials.  Please check your configuration. #{err.inspect}"
         | 
| 126 | 
            +
                    Cucumber::Chef.logger.fatal { message }
         | 
| 127 127 | 
             
                    raise ConfigError, message
         | 
| 128 128 | 
             
                  end
         | 
| 129 129 |  | 
| 130 130 | 
             
                  def self.verify_provider_vagrant
         | 
| 131 131 | 
             
                    message = "Not yet implemented."
         | 
| 132 | 
            -
                     | 
| 132 | 
            +
                    Cucumber::Chef.logger.fatal { message }
         | 
| 133 133 | 
             
                    raise ConfigError, message
         | 
| 134 134 | 
             
                  end
         | 
| 135 135 |  | 
| @@ -147,7 +147,7 @@ module Cucumber | |
| 147 147 | 
             
                      return ami.name if ami
         | 
| 148 148 | 
             
                    end
         | 
| 149 149 | 
             
                    message = "Could not find a valid AMI image ID.  Please check your configuration."
         | 
| 150 | 
            -
                     | 
| 150 | 
            +
                    Cucumber::Chef.logger.fatal { message }
         | 
| 151 151 | 
             
                    raise ConfigError, message
         | 
| 152 152 | 
             
                  end
         | 
| 153 153 |  | 
| @@ -2,7 +2,7 @@ | |
| 2 2 | 
             
            #
         | 
| 3 3 | 
             
            #      Author: Stephen Nelson-Smith <stephen@atalanta-systems.com>
         | 
| 4 4 | 
             
            #      Author: Zachary Patten <zachary@jovelabs.com>
         | 
| 5 | 
            -
            #   Copyright: Copyright (c) 2011- | 
| 5 | 
            +
            #   Copyright: Copyright (c) 2011-2013 Atalanta Systems Ltd
         | 
| 6 6 | 
             
            #     License: Apache License, Version 2.0
         | 
| 7 7 | 
             
            #
         | 
| 8 8 | 
             
            #   Licensed under the Apache License, Version 2.0 (the "License");
         | 
| @@ -26,26 +26,45 @@ module Cucumber::Chef::Helpers::ChefClient | |
| 26 26 | 
             
              # call this in a Before hook
         | 
| 27 27 | 
             
              def chef_set_client_config(config={})
         | 
| 28 28 | 
             
                @chef_client_config = (@chef_client_config || {
         | 
| 29 | 
            -
                  :log_level => : | 
| 29 | 
            +
                  :log_level => :info,
         | 
| 30 30 | 
             
                  :log_location => "/var/log/chef/client.log",
         | 
| 31 31 | 
             
                  :chef_server_url => "https://api.opscode.com/organizations/#{config[:orgname]}",
         | 
| 32 | 
            -
                  :validation_client_name => "#{config[:orgname]}-validator"
         | 
| 32 | 
            +
                  :validation_client_name => "#{config[:orgname]}-validator",
         | 
| 33 | 
            +
                  :ssl_verify_mode => :verify_none,
         | 
| 34 | 
            +
                  :environment => nil # use default; i.e. set no value
         | 
| 33 35 | 
             
                }).merge(config)
         | 
| 36 | 
            +
                log("setting chef client config $#{@chef_client_config.inspect}$")
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                true
         | 
| 34 39 | 
             
              end
         | 
| 35 40 |  | 
| 36 41 | 
             
            ################################################################################
         | 
| 37 42 |  | 
| 38 43 | 
             
              # call this before chef_run_client
         | 
| 39 44 | 
             
              def chef_set_client_attributes(name, attributes={})
         | 
| 40 | 
            -
                @ | 
| 45 | 
            +
                @servers[name] ||= Hash.new
         | 
| 46 | 
            +
                @servers[name][:chef_client] = (@servers[name][:chef_client] || {}).merge(attributes) { |k,o,n| (k = (o + n).uniq) }
         | 
| 47 | 
            +
                log("setting chef client attributes to $#{@servers[name][:chef_client].inspect}$ for container $#{name}$")
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                true
         | 
| 41 50 | 
             
              end
         | 
| 42 51 |  | 
| 43 52 | 
             
            ################################################################################
         | 
| 44 53 |  | 
| 45 54 | 
             
              def chef_run_client(name,*args)
         | 
| 46 55 | 
             
                chef_config_client(name)
         | 
| 47 | 
            -
                 | 
| 48 | 
            -
                log(" | 
| 56 | 
            +
                artifacts =
         | 
| 57 | 
            +
                log("removing artifacts #{Cucumber::Chef::Config[:artifacts].values.collect{|z| "$#{z}$" }.join(' ')}")
         | 
| 58 | 
            +
                (command_run_remote(name, "/bin/rm -fv #{Cucumber::Chef::Config[:artifacts].values.join(' ')}") rescue nil)
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                log("running chef client on container $#{name}$")
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                output = nil
         | 
| 63 | 
            +
                bm = ::Benchmark.realtime do
         | 
| 64 | 
            +
                  output = command_run_remote(name, ["/usr/bin/chef-client --json-attributes /etc/chef/attributes.json --node-name #{name}", args].flatten.join(" "))
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
                log("chef client run on container $#{name}$ took %0.4f seconds" % bm)
         | 
| 67 | 
            +
             | 
| 49 68 | 
             
                output
         | 
| 50 69 | 
             
              end
         | 
| 51 70 |  | 
| @@ -56,16 +75,15 @@ module Cucumber::Chef::Helpers::ChefClient | |
| 56 75 | 
             
                client_rb = File.join("/", container_root(name), "etc/chef/client.rb")
         | 
| 57 76 | 
             
                FileUtils.mkdir_p(File.dirname(client_rb))
         | 
| 58 77 |  | 
| 78 | 
            +
                max_key_size = @chef_client_config.keys.collect{ |z| z.to_s.size }.max
         | 
| 79 | 
            +
             | 
| 59 80 | 
             
                File.open(client_rb, 'w') do |f|
         | 
| 60 81 | 
             
                  f.puts(Cucumber::Chef.generate_do_not_edit_warning("Chef Client Configuration"))
         | 
| 61 82 | 
             
                  f.puts
         | 
| 62 | 
            -
                   | 
| 63 | 
            -
             | 
| 64 | 
            -
             | 
| 65 | 
            -
                   | 
| 66 | 
            -
                  f.puts("validation_client_name  \"#{@chef_client_config[:validation_client_name]}\"")
         | 
| 67 | 
            -
                  f.puts("node_name               \"#{name}\"")
         | 
| 68 | 
            -
                  f.puts("environment             \"#{@chef_client_config[:environment]}\"") if @chef_client_config[:environment]
         | 
| 83 | 
            +
                  @chef_client_config.merge(:node_name => name).each do |(key,value)|
         | 
| 84 | 
            +
                    next if value.nil?
         | 
| 85 | 
            +
                    f.puts("%-#{max_key_size}s  %s" % [key, value.inspect])
         | 
| 86 | 
            +
                  end
         | 
| 69 87 | 
             
                  f.puts
         | 
| 70 88 | 
             
                  f.puts("Mixlib::Log::Formatter.show_time = true")
         | 
| 71 89 | 
             
                end
         | 
| @@ -73,7 +91,7 @@ module Cucumber::Chef::Helpers::ChefClient | |
| 73 91 | 
             
                attributes_json = File.join("/", container_root(name), "etc", "chef", "attributes.json")
         | 
| 74 92 | 
             
                FileUtils.mkdir_p(File.dirname(attributes_json))
         | 
| 75 93 | 
             
                File.open(attributes_json, 'w') do |f|
         | 
| 76 | 
            -
                  f.puts((@ | 
| 94 | 
            +
                  f.puts((@servers[name][:chef_client] || {}).to_json)
         | 
| 77 95 | 
             
                end
         | 
| 78 96 |  | 
| 79 97 | 
             
                # make sure our log location is there
         | 
| @@ -81,6 +99,62 @@ module Cucumber::Chef::Helpers::ChefClient | |
| 81 99 | 
             
                FileUtils.mkdir_p(File.dirname(log_location))
         | 
| 82 100 |  | 
| 83 101 | 
             
                command_run_local("cp /etc/chef/validation.pem #{container_root(name)}/etc/chef/ 2>&1")
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                true
         | 
| 104 | 
            +
              end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
            ################################################################################
         | 
| 107 | 
            +
             | 
| 108 | 
            +
              def chef_client_artifacts(name)
         | 
| 109 | 
            +
                # this is messy and needs to be refactored into a more configurable
         | 
| 110 | 
            +
                # solution; but for now this should do the trick
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                ssh_private_key_file = Cucumber::Chef.locate(:file, ".cucumber-chef", "id_rsa-#{Cucumber::Chef::Config[:lab_user]}")
         | 
| 113 | 
            +
                File.chmod(0400, ssh_private_key_file)
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                ssh = ZTK::SSH.new
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                ssh.config.proxy_host_name = $test_lab.labs_running.first.public_ip_address
         | 
| 118 | 
            +
                ssh.config.proxy_user = Cucumber::Chef::Config[:lab_user]
         | 
| 119 | 
            +
                ssh.config.proxy_keys = ssh_private_key_file
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                ssh.config.host_name = name
         | 
| 122 | 
            +
                ssh.config.user = Cucumber::Chef::Config[:lxc_user]
         | 
| 123 | 
            +
                ssh.config.keys = ssh_private_key_file
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                feature_file = $scenario.file_colon_line.split(":").first
         | 
| 126 | 
            +
                feature_line = $scenario.file_colon_line.split(":").last
         | 
| 127 | 
            +
                scenario_tag = $scenario.name.gsub(" ", "_")
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                feature_name = File.basename(feature_file, ".feature")
         | 
| 130 | 
            +
                feature_dir = feature_file.split("/")[-2]
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                Cucumber::Chef::Config[:artifacts].each do |label, remote_path|
         | 
| 133 | 
            +
                  result = ssh.exec("/bin/bash -c '[[ -f #{remote_path} ]] ; echo $?'", :silence => true)
         | 
| 134 | 
            +
                  if (result.output =~ /0/)
         | 
| 135 | 
            +
                    log("retrieving artifact $#{remote_path}$ from container $#{name}$")
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                    local_path = File.join(Cucumber::Chef.locate(:directory, ".cucumber-chef"), "artifacts", feature_dir, "#{feature_name}.txt")
         | 
| 138 | 
            +
                    tmp_path = File.join("/tmp", label)
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                    FileUtils.mkdir_p(File.dirname(local_path))
         | 
| 141 | 
            +
                    ssh.download(remote_path, tmp_path)
         | 
| 142 | 
            +
                    data = IO.read(tmp_path).chomp
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                    message = "#{$scenario.name} (#{File.basename(feature_file)}:#{feature_line}:#{label})"
         | 
| 145 | 
            +
                    header = ("-" * message.length)
         | 
| 146 | 
            +
             | 
| 147 | 
            +
                    f = File.open(local_path, "a")
         | 
| 148 | 
            +
                    f.write("#{header}\n")
         | 
| 149 | 
            +
                    f.write("#{message}\n")
         | 
| 150 | 
            +
                    f.write("#{header}\n")
         | 
| 151 | 
            +
                    f.write("#{data}\n")
         | 
| 152 | 
            +
             | 
| 153 | 
            +
                    File.chmod(0644, local_path)
         | 
| 154 | 
            +
                  end
         | 
| 155 | 
            +
                end
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                true
         | 
| 84 158 | 
             
              end
         | 
| 85 159 |  | 
| 86 160 | 
             
            ################################################################################
         | 
| @@ -2,7 +2,7 @@ | |
| 2 2 | 
             
            #
         | 
| 3 3 | 
             
            #      Author: Stephen Nelson-Smith <stephen@atalanta-systems.com>
         | 
| 4 4 | 
             
            #      Author: Zachary Patten <zachary@jovelabs.com>
         | 
| 5 | 
            -
            #   Copyright: Copyright (c) 2011- | 
| 5 | 
            +
            #   Copyright: Copyright (c) 2011-2013 Atalanta Systems Ltd
         | 
| 6 6 | 
             
            #     License: Apache License, Version 2.0
         | 
| 7 7 | 
             
            #
         | 
| 8 8 | 
             
            #   Licensed under the Apache License, Version 2.0 (the "License");
         | 
| @@ -25,14 +25,14 @@ module Cucumber::Chef::Helpers::ChefServer | |
| 25 25 |  | 
| 26 26 | 
             
              def chef_server_node_destroy(name)
         | 
| 27 27 | 
             
                (::Chef::Node.load(name).destroy rescue nil)
         | 
| 28 | 
            -
                log("chef | 
| 28 | 
            +
                log("destroyed chef node $#{name}$")
         | 
| 29 29 | 
             
              end
         | 
| 30 30 |  | 
| 31 31 | 
             
            ################################################################################
         | 
| 32 32 |  | 
| 33 33 | 
             
              def chef_server_client_destroy(name)
         | 
| 34 34 | 
             
                (::Chef::ApiClient.load(name).destroy rescue nil)
         | 
| 35 | 
            -
                log("chef | 
| 35 | 
            +
                log("destroyed chef client $#{name}$")
         | 
| 36 36 | 
             
              end
         | 
| 37 37 |  | 
| 38 38 | 
             
            ################################################################################
         | 
| @@ -45,20 +45,37 @@ module Cucumber::Chef::Helpers::ChefServer | |
| 45 45 | 
             
                cookbook_repo.each do |name, cbook|
         | 
| 46 46 | 
             
                  next if name != cookbook
         | 
| 47 47 | 
             
                  ::Chef::CookbookUploader.new(cbook, cookbook_path, :force => true).upload_cookbooks
         | 
| 48 | 
            -
                  log("chef | 
| 48 | 
            +
                  log("uploaded chef cookbook $#{cookbook}$ from $#{cookbook_path}$")
         | 
| 49 49 | 
             
                end
         | 
| 50 50 | 
             
              end
         | 
| 51 51 |  | 
| 52 52 | 
             
            ################################################################################
         | 
| 53 53 |  | 
| 54 54 | 
             
              def load_role(role, role_path)
         | 
| 55 | 
            -
                 | 
| 56 | 
            -
             | 
| 55 | 
            +
                expanded_role_path = File.expand_path(role_path)
         | 
| 56 | 
            +
                if !File.exists?(expanded_role_path)
         | 
| 57 | 
            +
                  raise "Role path, '#{expanded_role_path}', does not exist!"
         | 
| 57 58 | 
             
                end
         | 
| 58 | 
            -
                ::Chef::Config[:role_path] =  | 
| 59 | 
            +
                ::Chef::Config[:role_path] = expanded_role_path
         | 
| 59 60 | 
             
                role = ::Chef::Role.from_disk(role)
         | 
| 60 61 | 
             
                role.save
         | 
| 61 | 
            -
                log("chef | 
| 62 | 
            +
                log("updated chef role $#{role}$ from $#{role_path}$")
         | 
| 63 | 
            +
              end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
            ################################################################################
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              def get_databag(databag)
         | 
| 68 | 
            +
                @rest ||= ::Chef::REST.new(Chef::Config[:chef_server_url])
         | 
| 69 | 
            +
                @rest.get_rest("data/#{databag}")
         | 
| 70 | 
            +
              rescue Net::HTTPServerException => e
         | 
| 71 | 
            +
                raise unless e.to_s =~ /^404/
         | 
| 72 | 
            +
              end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
              def destroy_databag(databag)
         | 
| 75 | 
            +
                @rest ||= ::Chef::REST.new(Chef::Config[:chef_server_url])
         | 
| 76 | 
            +
                @rest.delete_rest("data/#{databag}")
         | 
| 77 | 
            +
              rescue Net::HTTPServerException => e
         | 
| 78 | 
            +
                raise unless e.to_s =~ /^404/
         | 
| 62 79 | 
             
              end
         | 
| 63 80 |  | 
| 64 81 | 
             
            ################################################################################
         | 
| @@ -77,24 +94,30 @@ module Cucumber::Chef::Helpers::ChefServer | |
| 77 94 | 
             
              def load_databag(databag, databag_path)
         | 
| 78 95 | 
             
                create_databag(databag)
         | 
| 79 96 | 
             
                items = Dir.glob(File.expand_path(File.join(databag_path, "*.{json,rb}")))
         | 
| 97 | 
            +
                if (items.size == 0)
         | 
| 98 | 
            +
                  raise "Could not find any of the data bags you defined!"
         | 
| 99 | 
            +
                end
         | 
| 80 100 | 
             
                items.each do |item|
         | 
| 81 101 | 
             
                  next if File.directory?(item)
         | 
| 82 102 |  | 
| 103 | 
            +
                  item_name = %w( json rb ).collect{ |ext| (item =~ /#{ext}/ ? File.basename(item, ".#{ext}") : nil) }.compact.first
         | 
| 83 104 | 
             
                  item_path = File.basename(item)
         | 
| 84 105 | 
             
                  databag_item_path = File.expand_path(File.join(databag_path, item_path))
         | 
| 85 106 |  | 
| 86 107 | 
             
                  data_bag_item = ::Chef::DataBagItem.new
         | 
| 87 108 | 
             
                  data_bag_item.data_bag(databag)
         | 
| 88 | 
            -
                   | 
| 109 | 
            +
                  raw_data = load_databag_item(databag_item_path)
         | 
| 110 | 
            +
                  data_bag_item.raw_data = raw_data.dup
         | 
| 89 111 | 
             
                  data_bag_item.save
         | 
| 90 | 
            -
                  log("chef-server", "updated data bag item '#{databag}/#{item_path}' from file '#{databag_path}'")
         | 
| 91 | 
            -
                end
         | 
| 92 112 |  | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 113 | 
            +
                  loop do
         | 
| 114 | 
            +
                    chef_data = ::Chef::DataBagItem.load(databag, item_name).raw_data
         | 
| 115 | 
            +
                    break if chef_data == raw_data
         | 
| 116 | 
            +
                    log("waiting on chef data bag to update")
         | 
| 117 | 
            +
                    sleep(1)
         | 
| 118 | 
            +
                  end
         | 
| 119 | 
            +
                  log("updated chef data bag item $#{databag}/#{item_path}$ from $#{databag_path}$")
         | 
| 120 | 
            +
                end
         | 
| 98 121 | 
             
              end
         | 
| 99 122 |  | 
| 100 123 | 
             
            ################################################################################
         | 
| @@ -2,7 +2,7 @@ | |
| 2 2 | 
             
            #
         | 
| 3 3 | 
             
            #      Author: Stephen Nelson-Smith <stephen@atalanta-systems.com>
         | 
| 4 4 | 
             
            #      Author: Zachary Patten <zachary@jovelabs.com>
         | 
| 5 | 
            -
            #   Copyright: Copyright (c) 2011- | 
| 5 | 
            +
            #   Copyright: Copyright (c) 2011-2013 Atalanta Systems Ltd
         | 
| 6 6 | 
             
            #     License: Apache License, Version 2.0
         | 
| 7 7 | 
             
            #
         | 
| 8 8 | 
             
            #   Licensed under the Apache License, Version 2.0 (the "License");
         | 
| @@ -24,29 +24,45 @@ module Cucumber::Chef::Helpers::Command | |
| 24 24 | 
             
            ################################################################################
         | 
| 25 25 |  | 
| 26 26 | 
             
              def command_run_remote(name, command, expected_exit_code=0)
         | 
| 27 | 
            -
                 | 
| 28 | 
            -
                 | 
| 27 | 
            +
                command = %Q(ssh #{name} #{command} 2>&1)
         | 
| 28 | 
            +
                logger.info { "command_run_remote(#{command})" }
         | 
| 29 | 
            +
                output = %x(#{command})
         | 
| 30 | 
            +
                if !expected_exit_code.nil? && ($? != expected_exit_code)
         | 
| 31 | 
            +
                  message = "command_run_remote(#{command}) failed (code=#{$?},output='#{output.chomp}')"
         | 
| 32 | 
            +
                  logger.fatal { message }
         | 
| 33 | 
            +
                  logger.fatal { "output(#{output.chomp})" }
         | 
| 34 | 
            +
                  raise message
         | 
| 35 | 
            +
                end
         | 
| 29 36 | 
             
                output
         | 
| 30 | 
            -
            #  rescue RuntimeError => e
         | 
| 31 | 
            -
            #    if $? == 65280
         | 
| 32 | 
            -
            #      puts "Exit Code #{$?}: Retrying..."
         | 
| 33 | 
            -
            #      retry
         | 
| 34 | 
            -
            #    end
         | 
| 35 37 | 
             
              end
         | 
| 36 38 |  | 
| 37 39 | 
             
            ################################################################################
         | 
| 38 40 |  | 
| 39 41 | 
             
              def command_run_chroot(name, command, expected_exit_code=0)
         | 
| 40 | 
            -
                 | 
| 41 | 
            -
                 | 
| 42 | 
            +
                command = %Q(chroot #{container_root(name)} /bin/bash -c '#{command.gsub("'", '"')}' 2>&1)
         | 
| 43 | 
            +
                logger.info { "command_run_chroot(#{command})" }
         | 
| 44 | 
            +
                output = %x(#{command})
         | 
| 45 | 
            +
                if !expected_exit_code.nil? && ($? != expected_exit_code)
         | 
| 46 | 
            +
                  message = "command_run_chroot(#{command}) failed (#{$?})"
         | 
| 47 | 
            +
                  logger.fatal { message }
         | 
| 48 | 
            +
                  logger.fatal { "output(#{output.chomp})" }
         | 
| 49 | 
            +
                  raise message
         | 
| 50 | 
            +
                end
         | 
| 42 51 | 
             
                output
         | 
| 43 52 | 
             
              end
         | 
| 44 53 |  | 
| 45 54 | 
             
            ################################################################################
         | 
| 46 55 |  | 
| 47 56 | 
             
              def command_run_local(command, expected_exit_code=0)
         | 
| 48 | 
            -
                 | 
| 49 | 
            -
                 | 
| 57 | 
            +
                command = %Q(/bin/bash -c '#{command.gsub("'", '"')}' 2>&1)
         | 
| 58 | 
            +
                logger.info { "command_run_local(#{command})" }
         | 
| 59 | 
            +
                output = %x(#{command})
         | 
| 60 | 
            +
                if !expected_exit_code.nil? && ($? != expected_exit_code)
         | 
| 61 | 
            +
                  message = "command_run_local(#{command}) failed (#{$?})"
         | 
| 62 | 
            +
                  logger.fatal { message }
         | 
| 63 | 
            +
                  logger.fatal { "output(#{output.chomp})" }
         | 
| 64 | 
            +
                  raise message
         | 
| 65 | 
            +
                end
         | 
| 50 66 | 
             
                output
         | 
| 51 67 | 
             
              end
         | 
| 52 68 |  | 
| @@ -2,7 +2,7 @@ | |
| 2 2 | 
             
            #
         | 
| 3 3 | 
             
            #      Author: Stephen Nelson-Smith <stephen@atalanta-systems.com>
         | 
| 4 4 | 
             
            #      Author: Zachary Patten <zachary@jovelabs.com>
         | 
| 5 | 
            -
            #   Copyright: Copyright (c) 2011- | 
| 5 | 
            +
            #   Copyright: Copyright (c) 2011-2013 Atalanta Systems Ltd
         | 
| 6 6 | 
             
            #     License: Apache License, Version 2.0
         | 
| 7 7 | 
             
            #
         | 
| 8 8 | 
             
            #   Licensed under the Apache License, Version 2.0 (the "License");
         | 
| @@ -25,71 +25,74 @@ module Cucumber::Chef::Helpers::Container | |
| 25 25 |  | 
| 26 26 | 
             
              def container_create(name, distro, release, arch)
         | 
| 27 27 | 
             
                unless container_exists?(name)
         | 
| 28 | 
            -
                  chef_server_node_destroy(name)
         | 
| 29 | 
            -
                  chef_server_client_destroy(name)
         | 
| 30 | 
            -
             | 
| 31 28 | 
             
                  cache_rootfs = container_cache_root(name, distro, release, arch)
         | 
| 32 | 
            -
                   | 
| 29 | 
            +
                  if !File.exists?(cache_rootfs)
         | 
| 30 | 
            +
                    log("$#{name}$ has triggered building the lxc file cache for $#{distro}$")
         | 
| 31 | 
            +
                    log("this one time process per distro can take up to 10 minutes or longer depending on the test lab hardware")
         | 
| 32 | 
            +
                  end
         | 
| 33 33 |  | 
| 34 34 | 
             
                  command_run_local(container_create_command(name, distro, release, arch))
         | 
| 35 35 |  | 
| 36 36 | 
             
                  # install omnibus into the distro/release file cache if it's not already there
         | 
| 37 | 
            -
                  omnibus_chef_client = File.join("/", "opt", " | 
| 38 | 
            -
                   | 
| 37 | 
            +
                  omnibus_chef_client = File.join("/", "opt", "chef", "bin", "chef-client")
         | 
| 38 | 
            +
                  omnibus_cache = File.join(cache_rootfs, omnibus_chef_client)
         | 
| 39 | 
            +
                  logger.info { "looking for omnibus cache in #{omnibus_cache}" }
         | 
| 40 | 
            +
                  if !File.exists?(omnibus_cache)
         | 
| 39 41 | 
             
                    case distro.downcase
         | 
| 40 42 | 
             
                    when "ubuntu" then
         | 
| 41 | 
            -
                       | 
| 43 | 
            +
                      command_run_local("chroot #{cache_rootfs} /bin/bash -c 'apt-get -y --force-yes install wget'")
         | 
| 42 44 | 
             
                    when "fedora" then
         | 
| 43 | 
            -
                       | 
| 45 | 
            +
                      command_run_local("yum --nogpgcheck --installroot=#{cache_rootfs} -y install wget openssh-server")
         | 
| 44 46 | 
             
                    end
         | 
| 45 | 
            -
                     | 
| 47 | 
            +
                    command_run_local("chroot #{cache_rootfs} /bin/bash -c 'wget http://www.opscode.com/chef/install.sh -O - | bash'")
         | 
| 46 48 | 
             
                    if distro.downcase == "fedora"
         | 
| 47 | 
            -
                       | 
| 49 | 
            +
                      command_run_local("chroot #{cache_rootfs} /bin/bash -c 'rpm -Uvh --nodeps /tmp/*rpm'")
         | 
| 48 50 | 
             
                    end
         | 
| 49 | 
            -
                    command_run_local("lxc-destroy -n #{name} | 
| 51 | 
            +
                    command_run_local("lxc-destroy -n #{name}")
         | 
| 50 52 | 
             
                    command_run_local(container_create_command(name, distro, release, arch))
         | 
| 51 53 | 
             
                  end
         | 
| 52 54 |  | 
| 53 55 | 
             
                  command_run_local("mkdir -p #{container_root(name)}/root/.ssh")
         | 
| 54 56 | 
             
                  command_run_local("chmod 0755 #{container_root(name)}/root/.ssh")
         | 
| 55 57 | 
             
                  command_run_local("cat /root/.ssh/id_rsa.pub | tee -a #{container_root(name)}/root/.ssh/authorized_keys")
         | 
| 56 | 
            -
                  command_run_local("cat /home | 
| 58 | 
            +
                  command_run_local("cat /home/#{Cucumber::Chef::Config[:lab_user]}/.ssh/id_rsa.pub | tee -a #{container_root(name)}/root/.ssh/authorized_keys")
         | 
| 57 59 |  | 
| 58 | 
            -
                  command_run_local("mkdir -p #{container_root(name)}/home | 
| 59 | 
            -
                  command_run_local("chmod 0755 #{container_root(name)}/home | 
| 60 | 
            -
                  command_run_local("cat /root/.ssh/id_rsa.pub | tee -a #{container_root(name)}/home | 
| 61 | 
            -
                  command_run_local("cat /home | 
| 62 | 
            -
                  command_run_local("chown -R  | 
| 60 | 
            +
                  command_run_local("mkdir -p #{container_root(name)}/home/#{Cucumber::Chef::Config[:lab_user]}/.ssh")
         | 
| 61 | 
            +
                  command_run_local("chmod 0755 #{container_root(name)}/home/#{Cucumber::Chef::Config[:lab_user]}/.ssh")
         | 
| 62 | 
            +
                  command_run_local("cat /root/.ssh/id_rsa.pub | tee -a #{container_root(name)}/home/#{Cucumber::Chef::Config[:lab_user]}/.ssh/authorized_keys")
         | 
| 63 | 
            +
                  command_run_local("cat /home/#{Cucumber::Chef::Config[:lab_user]}/.ssh/id_rsa.pub | tee -a #{container_root(name)}/home/#{Cucumber::Chef::Config[:lab_user]}/.ssh/authorized_keys")
         | 
| 64 | 
            +
                  command_run_local("chown -R #{Cucumber::Chef::Config[:lab_user]}:#{Cucumber::Chef::Config[:lab_user]} #{container_root(name)}/home/#{Cucumber::Chef::Config[:lab_user]}/.ssh")
         | 
| 63 65 |  | 
| 64 66 | 
             
                  command_run_local("rm #{container_root(name)}/etc/motd")
         | 
| 65 67 | 
             
                  command_run_local("cp /etc/motd #{container_root(name)}/etc/motd")
         | 
| 66 | 
            -
                  command_run_local("echo  | 
| 67 | 
            -
                  command_run_local("sed -i  | 
| 68 | 
            -
                  command_run_local("echo  | 
| 68 | 
            +
                  command_run_local("echo '    You are now logged in to the #{name} container!\n' >> #{container_root(name)}/etc/motd")
         | 
| 69 | 
            +
                  command_run_local("sed -i 's/localhost #{name}/#{name}.test-lab #{name} localhost/' #{container_root(name)}/etc/hosts")
         | 
| 70 | 
            +
                  command_run_local("echo '#{name}.test-lab' | tee #{container_root(name)}/etc/hostname")
         | 
| 69 71 | 
             
                end
         | 
| 70 72 | 
             
                container_start(name)
         | 
| 71 73 | 
             
              end
         | 
| 72 74 |  | 
| 73 75 | 
             
              def container_destroy(name)
         | 
| 74 76 | 
             
                if container_exists?(name)
         | 
| 75 | 
            -
                  container_stop(name)
         | 
| 76 | 
            -
                  command_run_local("lxc-destroy -n #{name} 2>&1")
         | 
| 77 77 | 
             
                  chef_server_node_destroy(name)
         | 
| 78 78 | 
             
                  chef_server_client_destroy(name)
         | 
| 79 | 
            +
                  container_stop(name)
         | 
| 80 | 
            +
                  command_run_local("lxc-destroy -n #{name}")
         | 
| 81 | 
            +
                  log("destroyed container $#{name}$")
         | 
| 79 82 | 
             
                end
         | 
| 80 83 | 
             
              end
         | 
| 81 84 |  | 
| 82 85 | 
             
            ################################################################################
         | 
| 83 86 |  | 
| 84 87 | 
             
              def container_start(name)
         | 
| 85 | 
            -
                status = command_run_local("lxc-info -n #{name} | 
| 88 | 
            +
                status = command_run_local("lxc-info -n #{name}")
         | 
| 86 89 | 
             
                if status.include?("STOPPED")
         | 
| 87 90 | 
             
                  command_run_local("lxc-start -d -n #{name}")
         | 
| 88 91 | 
             
                end
         | 
| 89 92 | 
             
              end
         | 
| 90 93 |  | 
| 91 94 | 
             
              def container_stop(name)
         | 
| 92 | 
            -
                status = command_run_local("lxc-info -n #{name} | 
| 95 | 
            +
                status = command_run_local("lxc-info -n #{name}")
         | 
| 93 96 | 
             
                if status.include?("RUNNING")
         | 
| 94 97 | 
             
                  command_run_local("lxc-stop -n #{name}")
         | 
| 95 98 | 
             
                end
         | 
| @@ -98,7 +101,7 @@ module Cucumber::Chef::Helpers::Container | |
| 98 101 | 
             
            ################################################################################
         | 
| 99 102 |  | 
| 100 103 | 
             
              def container_running?(name)
         | 
| 101 | 
            -
                status = command_run_local("lxc-info -n #{name} | 
| 104 | 
            +
                status = command_run_local("lxc-info -n #{name}")
         | 
| 102 105 | 
             
                status.include?("RUNNING")
         | 
| 103 106 | 
             
              end
         | 
| 104 107 |  | 
| @@ -2,7 +2,7 @@ | |
| 2 2 | 
             
            #
         | 
| 3 3 | 
             
            #      Author: Stephen Nelson-Smith <stephen@atalanta-systems.com>
         | 
| 4 4 | 
             
            #      Author: Zachary Patten <zachary@jovelabs.com>
         | 
| 5 | 
            -
            #   Copyright: Copyright (c) 2011- | 
| 5 | 
            +
            #   Copyright: Copyright (c) 2011-2013 Atalanta Systems Ltd
         | 
| 6 6 | 
             
            #     License: Apache License, Version 2.0
         | 
| 7 7 | 
             
            #
         | 
| 8 8 | 
             
            #   Licensed under the Apache License, Version 2.0 (the "License");
         |