lib/ridley/resources/node_resource.rb in ridley-0.10.2 vs lib/ridley/resources/node_resource.rb in ridley-0.11.0.rc1
- old
+ new
@@ -1,348 +1,172 @@
module Ridley
# @author Jamie Winsor <reset@riotgames.com>
class NodeResource < Ridley::Resource
- class << self
- # @overload bootstrap(client, nodes, options = {})
- # @param [Ridley::Client] client
- # @param [Array<String>, String] nodes
- # @param [Hash] ssh
- # * :user (String) a shell user that will login to each node and perform the bootstrap command on (required)
- # * :password (String) the password for the shell user that will perform the bootstrap
- # * :keys (Array, String) an array of keys (or a single key) to authenticate the ssh user with instead of a password
- # * :timeout (Float) [5.0] timeout value for SSH bootstrap
- # @option options [Hash] :winrm
- # * :user (String) a user that will login to each node and perform the bootstrap command on (required)
- # * :password (String) the password for the user that will perform the bootstrap
- # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
- # @option options [String] :validator_client
- # @option options [String] :validator_path
- # filepath to the validator used to bootstrap the node (required)
- # @option options [String] :bootstrap_proxy
- # URL to a proxy server to bootstrap through (default: nil)
- # @option options [String] :encrypted_data_bag_secret_path
- # filepath on your host machine to your organizations encrypted data bag secret (default: nil)
- # @option options [Hash] :hints
- # a hash of Ohai hints to place on the bootstrapped node (default: Hash.new)
- # @option options [Hash] :attributes
- # a hash of attributes to use in the first Chef run (default: Hash.new)
- # @option options [Array] :run_list
- # an initial run list to bootstrap with (default: Array.new)
- # @option options [String] :chef_version
- # version of Chef to install on the node (default: nil)
- # @option options [String] :environment
- # environment to join the node to (default: '_default')
- # @option options [Boolean] :sudo
- # bootstrap with sudo (default: true)
- # @option options [String] :template
- # bootstrap template to use (default: omnibus)
- #
- # @return [SSH::ResponseSet]
- def bootstrap(client, *args)
- options = args.extract_options!
-
- default_options = {
- server_url: client.server_url,
- validator_path: client.validator_path,
- validator_client: client.validator_client,
- encrypted_data_bag_secret_path: client.encrypted_data_bag_secret_path,
- ssh: client.ssh,
- winrm: client.winrm,
- chef_version: client.chef_version
- }
-
- options = default_options.merge(options)
- Bootstrapper.new(args, options).run
- end
-
- # Executes a Chef run using the best worker available for the given
- # host.
- #
- # @param [Ridley::Client] client
- # @param [String] host
- #
- # @return [HostConnector::Response]
- def chef_run(client, host)
- worker = configured_worker_for(client, host)
- worker.chef_client
- ensure
- worker.terminate if worker && worker.alive?
- end
-
- # Puts a secret on the host using the best worker available for
- # the given host.
- #
- # @param [Ridley::Client] client
- # @param [String] host
- # @param [String] encrypted_data_bag_secret_path
- #
- # @return [HostConnector::Response]
- def put_secret(client, host, encrypted_data_bag_secret_path)
- worker = configured_worker_for(client, host)
- worker.put_secret(encrypted_data_bag_secret_path)
- ensure
- worker.terminate if worker && worker.alive?
- end
-
- # Executes an arbitrary ruby script using the best worker available
- # for the given host.
- #
- # @param [Ridley::Client] client
- # @param [String] host
- # @param [Array<String>] command_lines
- #
- # @return [HostConnector::Response]
- def ruby_script(client, host, command_lines)
- worker = configured_worker_for(client, host)
- worker.ruby_script(command_lines)
- ensure
- worker.terminate if worker && worker.alive?
- end
-
- # Executes the given command on a node using the best worker
- # available for the given host.
- #
- # @param [Ridley::Client] client
- # @param [String] host
- # @param [String] command
- #
- # @return [Array<Symbol, HostConnector::Response>]
- def execute_command(client, host, command)
- worker = configured_worker_for(client, host)
- worker.run(command)
- ensure
- worker.terminate if worker && worker.alive?
- end
-
- # Merges the given data with the the data of the target node on the remote
- #
- # @param [Ridley::Client] client
- # @param [Ridley::NodeResource, String] target
- # node or identifier of the node to merge
- #
- # @option options [Array] :run_list
- # run list items to merge
- # @option options [Hash] :attributes
- # attributes of normal precedence to merge
- #
- # @raise [Errors::HTTPNotFound]
- # if the target node is not found
- #
- # @return [Ridley::NodeResource]
- def merge_data(client, target, options = {})
- find!(client, target).merge_data(options)
- end
-
- private
- # @param [Ridley::Client] client
- # @param [String] host
- #
- # @return [SSH::Worker, WinRM::Worker]
- def configured_worker_for(client, host)
- connector_options = Hash.new
- connector_options[:ssh] = client.ssh
- connector_options[:winrm] = client.winrm
-
- HostConnector.best_connector_for(host, connector_options) do |host_connector|
- host_connector::Worker.new(host, connector_options)
- end
- end
- end
-
include Ridley::Logging
- set_chef_id "name"
- set_chef_type "node"
- set_chef_json_class "Chef::Node"
set_resource_path "nodes"
+ represented_by Ridley::NodeObject
- attribute :name,
- required: true
+ attr_reader :server_url
+ attr_reader :validator_path
+ attr_reader :validator_client
+ attr_reader :encrypted_data_bag_secret
+ attr_reader :ssh
+ attr_reader :winrm
+ attr_reader :chef_version
- attribute :chef_environment,
- default: "_default"
-
- attribute :automatic,
- default: Hashie::Mash.new
-
- attribute :normal,
- default: Hashie::Mash.new
-
- attribute :default,
- default: Hashie::Mash.new
-
- attribute :override,
- default: Hashie::Mash.new
-
- attribute :run_list,
- default: Array.new
-
- alias_method :normal_attributes, :normal
- alias_method :automatic_attributes, :automatic
- alias_method :default_attributes, :default
- alias_method :override_attributes, :override
-
- alias_method :normal_attributes=, :normal=
- alias_method :automatic_attributes=, :automatic=
- alias_method :default_attributes=, :default=
- alias_method :override_attributes=, :override=
-
- # Set a node level normal attribute given the dotted path representation of the Chef
- # attribute and value.
+ # @param [Celluloid::Registry] connection_registry
#
- # @note It is not possible to set any other attribute level on a node and have it persist after
- # a Chef Run. This is because all other attribute levels are truncated at the start of a Chef Run.
- #
- # @example setting and saving a node level normal attribute
- #
- # obj = node.find("jwinsor-1")
- # obj.set_chef_attribute("my_app.billing.enabled", false)
- # obj.save
- #
- # @param [String] key
- # @param [Object] value
- #
- # @return [Hashie::Mash]
- def set_chef_attribute(key, value)
- attr_hash = Hashie::Mash.from_dotted_path(key, value)
- self.normal = self.normal.deep_merge(attr_hash)
+ # @option options [String] :server_url
+ # URL to the Chef API
+ # @option options [Hash] ssh
+ # * :user (String) a shell user that will login to each node and perform the bootstrap command on
+ # * :password (String) the password for the shell user that will perform the bootstrap
+ # * :keys (Array, String) an array of keys (or a single key) to authenticate the ssh user with instead of a password
+ # * :timeout (Float) [5.0] timeout value for SSH bootstrap
+ # @option options [Hash] :winrm
+ # * :user (String) a user that will login to each node and perform the bootstrap command on
+ # * :password (String) the password for the user that will perform the bootstrap
+ # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on
+ # @option options [String] :validator_client
+ # @option options [String] :validator_path
+ # filepath to the validator used to bootstrap the node
+ # @option options [String] :encrypted_data_bag_secret
+ # your organizations encrypted data bag secret
+ # @option options [String] :chef_version
+ # version of Chef to install on the node (default: nil)
+ def initialize(connection_registry, options = {})
+ super(connection_registry)
+ @server_url = options[:server_url]
+ @validator_path = options[:validator_path]
+ @validator_client = options[:validator_client]
+ @encrypted_data_bag_secret = options[:encrypted_data_bag_secret]
+ @ssh = options[:ssh]
+ @winrm = options[:winrm]
+ @chef_version = options[:chef_version]
end
- # Returns the public hostname of the instantiated node. This hostname should be used for
- # public communications to the node.
+ # @overload bootstrap(nodes, options = {})
+ # @param [Array<String>, String] nodes
#
- # @example
- # node.public_hostname => "reset.riotgames.com"
+ # @option options [Hash] ssh
+ # * :user (String) a shell user that will login to each node and perform the bootstrap command on (required)
+ # * :password (String) the password for the shell user that will perform the bootstrap
+ # * :keys (Array, String) an array of keys (or a single key) to authenticate the ssh user with instead of a password
+ # * :timeout (Float) [5.0] timeout value for SSH bootstrap
+ # @option options [Hash] :winrm
+ # * :user (String) a user that will login to each node and perform the bootstrap command on (required)
+ # * :password (String) the password for the user that will perform the bootstrap
+ # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
+ # @option options [String] :validator_client
+ # @option options [String] :validator_path
+ # filepath to the validator used to bootstrap the node (required)
+ # @option options [String] :bootstrap_proxy
+ # URL to a proxy server to bootstrap through (default: nil)
+ # @option options [String] :encrypted_data_bag_secret_path
+ # filepath on your host machine to your organizations encrypted data bag secret (default: nil)
+ # @option options [Hash] :hints
+ # a hash of Ohai hints to place on the bootstrapped node (default: Hash.new)
+ # @option options [Hash] :attributes
+ # a hash of attributes to use in the first Chef run (default: Hash.new)
+ # @option options [Array] :run_list
+ # an initial run list to bootstrap with (default: Array.new)
+ # @option options [String] :chef_version
+ # version of Chef to install on the node (default: nil)
+ # @option options [String] :environment
+ # environment to join the node to (default: '_default')
+ # @option options [Boolean] :sudo
+ # bootstrap with sudo (default: true)
+ # @option options [String] :template
+ # bootstrap template to use (default: omnibus)
#
- # @return [String]
- def public_hostname
- self.cloud? ? self.automatic[:cloud][:public_hostname] : self.automatic[:fqdn]
- end
+ # @return [SSH::ResponseSet]
+ def bootstrap(*args)
+ args = args.dup
+ opts = args.extract_options!
- # Returns the public IPv4 address of the instantiated node. This ip address should be
- # used for public communications to the node.
- #
- # @example
- # node.public_ipv4 => "10.33.33.1"
- #
- # @return [String]
- def public_ipv4
- self.cloud? ? self.automatic[:cloud][:public_ipv4] : self.automatic[:ipaddress]
- end
- alias_method :public_ipaddress, :public_ipv4
+ options = opts.reverse_merge(
+ server_url: server_url,
+ validator_path: validator_path,
+ validator_client: validator_client,
+ encrypted_data_bag_secret: encrypted_data_bag_secret,
+ ssh: ssh,
+ winrm: winrm,
+ chef_version: chef_version
+ )
- # Returns the cloud provider of the instantiated node. If the node is not identified as
- # a cloud node, then nil is returned.
- #
- # @example
- # node_1.cloud_provider => "eucalyptus"
- # node_2.cloud_provider => "ec2"
- # node_3.cloud_provider => "rackspace"
- # node_4.cloud_provider => nil
- #
- # @return [nil, String]
- def cloud_provider
- self.cloud? ? self.automatic[:cloud][:provider] : nil
+ Bootstrapper.new(args, options).run
end
- # Returns true if the node is identified as a cloud node.
+ # Executes a Chef run using the best worker available for the given
+ # host.
#
- # @return [Boolean]
- def cloud?
- self.automatic.has_key?(:cloud)
- end
-
- # Returns true if the node is identified as a cloud node using the eucalyptus provider.
+ # @param [String] host
#
- # @return [Boolean]
- def eucalyptus?
- self.cloud_provider == "eucalyptus"
+ # @return [HostConnector::Response]
+ def chef_run(host)
+ worker = HostConnector.new(host, ssh: ssh, winrm: winrm)
+ worker.chef_client
+ ensure
+ worker.terminate if worker && worker.alive?
end
- # Returns true if the node is identified as a cloud node using the ec2 provider.
+ # Puts a secret on the host using the best worker available for
+ # the given host.
#
- # @return [Boolean]
- def ec2?
- self.cloud_provider == "ec2"
- end
-
- # Returns true if the node is identified as a cloud node using the rackspace provider.
+ # @param [String] host
#
- # @return [Boolean]
- def rackspace?
- self.cloud_provider == "rackspace"
+ # @return [HostConnector::Response]
+ def put_secret(host)
+ worker = HostConnector.new(host, ssh: ssh, winrm: winrm)
+ worker.put_secret(encrypted_data_bag_secret)
+ ensure
+ worker.terminate if worker && worker.alive?
end
- # Run Chef-Client on the instantiated node.
+ # Executes an arbitrary ruby script using the best worker available
+ # for the given host.
#
- # @param [Hash] options
- # a hash of options to pass to the best {Ridley::HostConnector}
+ # @param [String] host
+ # @param [Array<String>] command_lines
#
# @return [HostConnector::Response]
- def chef_client(options = {})
- connector_options = Hash.new
- connector_options[:ssh] = client.ssh
- connector_options[:winrm] = client.winrm
- connector_options.merge(options)
-
- log.debug "Running Chef Client on: #{self.public_hostname}"
-
- HostConnector.best_connector_for(self.public_hostname, connector_options) do |host_connector|
- host_connector.start(self, connector_options) do |connector|
- _, response = connector.chef_client
- response
- end
- end
+ def ruby_script(host, command_lines)
+ worker = HostConnector.new(host, ssh: ssh, winrm: winrm)
+ worker.ruby_script(command_lines)
+ ensure
+ worker.terminate if worker && worker.alive?
end
- # Put the client's encrypted data bag secret onto the instantiated node. If no
- # encrypted data bag key path is set on the resource's client then nil will be
- # returned
+ # Executes the given command on a node using the best worker
+ # available for the given host.
#
- # @param [Hash] options
- # a hash of options to pass to the best {Ridley::HostConnector}
+ # @param [String] host
+ # @param [String] command
#
- # @return [HostConnector::Response, nil]
- def put_secret(options = {})
- if client.encrypted_data_bag_secret_path.nil? ||
- !File.exists?(client.encrypted_data_bag_secret_path)
-
- return nil
- end
-
- connector_options = Hash.new
- connector_options[:ssh] = client.ssh
- connector_options[:winrm] = client.winrm
-
- log.debug "Writing Encrypted Data Bag Secret to: #{self.public_hostname}"
-
- HostConnector.best_connector_for(self.public_hostname, connector_options) do |host_connector|
- host_connector.start(self, connector_options) do |connector|
- _, response = connector.put_secret(client.encrypted_data_bag_secret_path)
- response
- end
- end
+ # @return [Array<Symbol, HostConnector::Response>]
+ def execute_command(host, command)
+ worker = HostConnector.new(host, ssh: ssh, winrm: winrm)
+ worker.run(command)
+ ensure
+ worker.terminate if worker && worker.alive?
end
- # Merges the instaniated nodes data with the given data and updates
- # the remote with the merged results
+ # Merges the given data with the the data of the target node on the remote
#
+ # @param [Ridley::NodeResource, String] target
+ # node or identifier of the node to merge
+ #
# @option options [Array] :run_list
# run list items to merge
# @option options [Hash] :attributes
# attributes of normal precedence to merge
#
+ # @raise [Errors::HTTPNotFound]
+ # if the target node is not found
+ #
# @return [Ridley::NodeResource]
- def merge_data(options = {})
- unless options[:run_list].nil?
- self.run_list = (self.run_list + Array(options[:run_list])).uniq
- end
-
- unless options[:attributes].nil?
- self.normal = self.normal.deep_merge(options[:attributes])
- end
-
- self.update
- self
+ def merge_data(target, options = {})
+ find(target).merge_data(options)
end
end
end