lib/chef/knife/ec2_server_create.rb in knife-ec2-0.18.2 vs lib/chef/knife/ec2_server_create.rb in knife-ec2-0.19.10

- old
+ new

@@ -1,9 +1,9 @@ # # Author:: Adam Jacob (<adam@chef.io>) # Author:: Seth Chisamore (<schisamo@chef.io>) -# Copyright:: Copyright (c) 2010-2015 Chef Software, Inc. +# Copyright:: Copyright (c) 2010-2018 Chef Software, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -15,474 +15,453 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # -require 'chef/knife/ec2_base' -require 'chef/knife/s3_source' -require 'chef/knife/winrm_base' -require 'chef/knife/bootstrap_windows_base' +require "chef/knife/ec2_base" +require "chef/knife/s3_source" +require "chef/knife/winrm_base" +require "chef/knife/bootstrap_windows_base" class Chef class Knife class Ec2ServerCreate < Knife include Knife::Ec2Base include Knife::WinrmBase include Knife::BootstrapWindowsBase deps do - require 'tempfile' - require 'fog/aws' - require 'uri' - require 'readline' - require 'chef/json_compat' - require 'chef/knife/bootstrap' + require "tempfile" + require "uri" + require "chef/knife/bootstrap" Chef::Knife::Bootstrap.load_deps end banner "knife ec2 server create (options)" attr_accessor :initial_sleep_delay attr_reader :server option :flavor, - :short => "-f FLAVOR", - :long => "--flavor FLAVOR", - :description => "The flavor of server (m1.small, m1.medium, etc)", - :proc => Proc.new { |f| Chef::Config[:knife][:flavor] = f } + short: "-f FLAVOR", + long: "--flavor FLAVOR", + description: "The flavor of server (m1.small, m1.medium, etc)", + proc: Proc.new { |f| Chef::Config[:knife][:flavor] = f } option :image, - :short => "-I IMAGE", - :long => "--image IMAGE", - :description => "The AMI for the server", - :proc => Proc.new { |i| Chef::Config[:knife][:image] = i } + short: "-I IMAGE", + long: "--image IMAGE", + description: "The AMI for the server", + proc: Proc.new { |i| Chef::Config[:knife][:image] = i } option :iam_instance_profile, - :long => "--iam-profile NAME", - :description => "The IAM instance profile to apply to this instance." + long: "--iam-profile NAME", + description: "The IAM instance profile to apply to this instance." option :security_groups, - :short => "-G X,Y,Z", - :long => "--groups X,Y,Z", - :description => "The security groups for this server; not allowed when using VPC", - :proc => Proc.new { |groups| groups.split(',') } + short: "-G X,Y,Z", + long: "--groups X,Y,Z", + description: "The security groups for this server; not allowed when using VPC", + proc: Proc.new { |groups| groups.split(",") } option :security_group_ids, - :long => "--security-group-ids 'X,Y,Z'", - :description => "The security group ids for this server; required when using VPC. Provide values in format --security-group-ids 'X,Y,Z'. [DEPRECATED] This option will be removed in future release. Use the new --security-group-id option. ", - :proc => Proc.new { |security_group_ids| - ui.warn('[DEPRECATED] This option will be removed in future release. Use the new --security-group-id option multiple times when specifying multiple groups for e.g. -g sg-e985168d -g sg-e7f06383 -g sg-ec1b7e88.') - if security_group_ids.gsub(' ', '').split(',').size > 1 - Chef::Config[:knife][:security_group_ids] = security_group_ids.gsub(' ', '').split(',') + long: "--security-group-ids 'X,Y,Z'", + description: "The security group ids for this server; required when using VPC. Provide values in format --security-group-ids 'X,Y,Z'. [DEPRECATED] This option will be removed in future release. Use the new --security-group-id option. ", + proc: Proc.new { |security_group_ids| + ui.warn("[DEPRECATED] This option will be removed in future release. Use the new --security-group-id option multiple times when specifying multiple groups for e.g. -g sg-e985168d -g sg-e7f06383 -g sg-ec1b7e88.") + if security_group_ids.delete(" ").split(",").size > 1 + Chef::Config[:knife][:security_group_ids] = security_group_ids.delete(" ").split(",") else Chef::Config[:knife][:security_group_ids] ||= [] Chef::Config[:knife][:security_group_ids].push(security_group_ids) Chef::Config[:knife][:security_group_ids] end } option :security_group_id, - :short => "-g SECURITY_GROUP_ID", - :long => "--security-group-id ID", - :description => "The security group id for this server; required when using VPC. Use the --security-group-id option multiple times when specifying multiple groups for e.g. -g sg-e985168d -g sg-e7f06383 -g sg-ec1b7e88.", - :proc => Proc.new { |security_group_id| + short: "-g SECURITY_GROUP_ID", + long: "--security-group-id ID", + description: "The security group id for this server; required when using VPC. Use the --security-group-id option multiple times when specifying multiple groups for e.g. -g sg-e985168d -g sg-e7f06383 -g sg-ec1b7e88.", + proc: Proc.new { |security_group_id| Chef::Config[:knife][:security_group_ids] ||= [] Chef::Config[:knife][:security_group_ids].push(security_group_id) Chef::Config[:knife][:security_group_ids] } option :associate_eip, - :long => "--associate-eip IP_ADDRESS", - :description => "Associate existing elastic IP address with instance after launch" + long: "--associate-eip IP_ADDRESS", + description: "Associate existing elastic IP address with instance after launch" option :dedicated_instance, - :long => "--dedicated_instance", - :description => "Launch as a Dedicated instance (VPC ONLY)" + long: "--dedicated_instance", + description: "Launch as a Dedicated instance (VPC ONLY)" option :placement_group, - :long => "--placement-group PLACEMENT_GROUP", - :description => "The placement group to place a cluster compute instance", - :proc => Proc.new { |pg| Chef::Config[:knife][:placement_group] = pg } + long: "--placement-group PLACEMENT_GROUP", + description: "The placement group to place a cluster compute instance", + proc: Proc.new { |pg| Chef::Config[:knife][:placement_group] = pg } option :primary_eni, - :long => "--primary-eni ENI_ID", - :description => "Specify a pre-existing eni to use when building the instance." + long: "--primary-eni ENI_ID", + description: "Specify a pre-existing eni to use when building the instance." option :tags, - :short => "-T T=V[,T=V,...]", - :long => "--tags Tag=Value[,Tag=Value...]", - :description => "The tags for this server. [DEPRECATED] Use --aws-tag instead.", - :proc => Proc.new { |tags| + short: "-T T=V[,T=V,...]", + long: "--tags Tag=Value[,Tag=Value...]", + description: "The tags for this server. [DEPRECATED] Use --aws-tag instead.", + proc: Proc.new { |tags| Chef::Log.warn("[DEPRECATED] --tags option is deprecated. Use --aws-tag option instead.") - tags.split(',') + tags.split(",") } option :availability_zone, - :short => "-Z ZONE", - :long => "--availability-zone ZONE", - :description => "The Availability Zone", - :proc => Proc.new { |key| Chef::Config[:knife][:availability_zone] = key } + short: "-Z ZONE", + long: "--availability-zone ZONE", + description: "The Availability Zone", + proc: Proc.new { |key| Chef::Config[:knife][:availability_zone] = key } option :chef_node_name, - :short => "-N NAME", - :long => "--node-name NAME", - :description => "The Chef node name for your new node", - :proc => Proc.new { |key| Chef::Config[:knife][:chef_node_name] = key } + short: "-N NAME", + long: "--node-name NAME", + description: "The Chef node name for your new node", + proc: Proc.new { |key| Chef::Config[:knife][:chef_node_name] = key } option :ssh_key_name, - :short => "-S KEY", - :long => "--ssh-key KEY", - :description => "The AWS SSH key id", - :proc => Proc.new { |key| Chef::Config[:knife][:ssh_key_name] = key } + short: "-S KEY", + long: "--ssh-key KEY", + description: "The AWS SSH key id", + proc: Proc.new { |key| Chef::Config[:knife][:ssh_key_name] = key } option :ssh_user, - :short => "-x USERNAME", - :long => "--ssh-user USERNAME", - :description => "The ssh username", - :default => "root" + short: "-x USERNAME", + long: "--ssh-user USERNAME", + description: "The ssh username", + default: "root" option :ssh_password, - :short => "-P PASSWORD", - :long => "--ssh-password PASSWORD", - :description => "The ssh password" + short: "-P PASSWORD", + long: "--ssh-password PASSWORD", + description: "The ssh password" option :ssh_port, - :short => "-p PORT", - :long => "--ssh-port PORT", - :description => "The ssh port", - :default => "22", - :proc => Proc.new { |key| Chef::Config[:knife][:ssh_port] = key } + short: "-p PORT", + long: "--ssh-port PORT", + description: "The ssh port", + default: "22", + proc: Proc.new { |key| Chef::Config[:knife][:ssh_port] = key } option :ssh_gateway, - :short => "-w GATEWAY", - :long => "--ssh-gateway GATEWAY", - :description => "The ssh gateway server. Any proxies configured in your ssh config are automatically used by default.", - :proc => Proc.new { |key| Chef::Config[:knife][:ssh_gateway] = key } + short: "-w GATEWAY", + long: "--ssh-gateway GATEWAY", + description: "The ssh gateway server. Any proxies configured in your ssh config are automatically used by default.", + proc: Proc.new { |key| Chef::Config[:knife][:ssh_gateway] = key } option :ssh_gateway_identity, - :long => "--ssh-gateway-identity IDENTITY_FILE", - :description => "The private key for ssh gateway server", - :proc => Proc.new { |key| Chef::Config[:knife][:ssh_gateway_identity] = key } + long: "--ssh-gateway-identity IDENTITY_FILE", + description: "The private key for ssh gateway server", + proc: Proc.new { |key| Chef::Config[:knife][:ssh_gateway_identity] = key } option :identity_file, - :short => "-i IDENTITY_FILE", - :long => "--identity-file IDENTITY_FILE", - :description => "The SSH identity file used for authentication" + short: "-i IDENTITY_FILE", + long: "--identity-file IDENTITY_FILE", + description: "The SSH identity file used for authentication" option :prerelease, - :long => "--prerelease", - :description => "Install the pre-release chef gems" + long: "--prerelease", + description: "Install the pre-release chef gems" option :bootstrap_version, - :long => "--bootstrap-version VERSION", - :description => "The version of Chef to install", - :proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_version] = v } + long: "--bootstrap-version VERSION", + description: "The version of Chef to install", + proc: Proc.new { |v| Chef::Config[:knife][:bootstrap_version] = v } option :bootstrap_proxy, - :long => "--bootstrap-proxy PROXY_URL", - :description => "The proxy server for the node being bootstrapped", - :proc => Proc.new { |p| Chef::Config[:knife][:bootstrap_proxy] = p } + long: "--bootstrap-proxy PROXY_URL", + description: "The proxy server for the node being bootstrapped", + proc: Proc.new { |p| Chef::Config[:knife][:bootstrap_proxy] = p } - option :distro, - :short => "-d DISTRO", - :long => "--distro DISTRO", - :description => "Bootstrap a distro using a template. [DEPRECATED] Use --bootstrap-template option instead.", - :proc => Proc.new { |v| - Chef::Log.warn("[DEPRECATED] -d / --distro option is deprecated. Use --bootstrap-template option instead.") - v - } - - option :template_file, - :long => "--template-file TEMPLATE", - :description => "Full path to location of template to use. [DEPRECATED] Use -t / --bootstrap-template option instead.", - :proc => Proc.new { |v| - Chef::Log.warn("[DEPRECATED] --template-file option is deprecated. Use -t / --bootstrap-template option instead.") - v - } - option :bootstrap_template, - :long => "--bootstrap-template TEMPLATE", - :description => "Bootstrap Chef using a built-in or custom template. Set to the full path of an erb template or use one of the built-in templates." + long: "--bootstrap-template TEMPLATE", + description: "Bootstrap Chef using a built-in or custom template. Set to the full path of an erb template or use one of the built-in templates." option :ebs_size, - :long => "--ebs-size SIZE", - :description => "The size of the EBS volume in GB, for EBS-backed instances" + long: "--ebs-size SIZE", + description: "The size of the EBS volume in GB, for EBS-backed instances" option :ebs_optimized, - :long => "--ebs-optimized", - :description => "Enabled optimized EBS I/O" + long: "--ebs-optimized", + description: "Enabled optimized EBS I/O" option :ebs_no_delete_on_term, - :long => "--ebs-no-delete-on-term", - :description => "Do not delete EBS volume on instance termination" + long: "--ebs-no-delete-on-term", + description: "Do not delete EBS volume on instance termination" option :run_list, - :short => "-r RUN_LIST", - :long => "--run-list RUN_LIST", - :description => "Comma separated list of roles/recipes to apply", - :proc => lambda { |o| o.split(/[\s,]+/) }, - :default => [] + short: "-r RUN_LIST", + long: "--run-list RUN_LIST", + description: "Comma separated list of roles/recipes to apply", + proc: lambda { |o| o.split(/[\s,]+/) }, + default: [] option :secret, - :long => "--secret ", - :description => "The secret key to use to encrypt data bag item values", - :proc => lambda { |s| Chef::Config[:knife][:secret] = s } + long: "--secret ", + description: "The secret key to use to encrypt data bag item values", + proc: lambda { |s| Chef::Config[:knife][:secret] = s } option :secret_file, - :long => "--secret-file SECRET_FILE", - :description => "A file containing the secret key to use to encrypt data bag item values", - :proc => lambda { |sf| Chef::Config[:knife][:secret_file] = sf } + long: "--secret-file SECRET_FILE", + description: "A file containing the secret key to use to encrypt data bag item values", + proc: lambda { |sf| Chef::Config[:knife][:secret_file] = sf } option :s3_secret, - :long => '--s3-secret S3_SECRET_URL', - :description => 'S3 URL (e.g. s3://bucket/file) for the encrypted_data_bag_secret_file', - :proc => lambda { |url| Chef::Config[:knife][:s3_secret] = url } + long: "--s3-secret S3_SECRET_URL", + description: "S3 URL (e.g. s3://bucket/file) for the encrypted_data_bag_secret_file", + proc: lambda { |url| Chef::Config[:knife][:s3_secret] = url } option :subnet_id, - :long => "--subnet SUBNET-ID", - :description => "create node in this Virtual Private Cloud Subnet ID (implies VPC mode)", - :proc => Proc.new { |key| Chef::Config[:knife][:subnet_id] = key } + long: "--subnet SUBNET-ID", + description: "create node in this Virtual Private Cloud Subnet ID (implies VPC mode)", + proc: Proc.new { |key| Chef::Config[:knife][:subnet_id] = key } option :private_ip_address, - :long => "--private-ip-address IP-ADDRESS", - :description => "allows to specify the private IP address of the instance in VPC mode", - :proc => Proc.new { |ip| Chef::Config[:knife][:private_ip_address] = ip } + long: "--private-ip-address IP-ADDRESS", + description: "allows to specify the private IP address of the instance in VPC mode", + proc: Proc.new { |ip| Chef::Config[:knife][:private_ip_address] = ip } option :host_key_verify, - :long => "--[no-]host-key-verify", - :description => "Verify host key, enabled by default.", - :boolean => true, - :default => true + long: "--[no-]host-key-verify", + description: "Verify host key, enabled by default.", + boolean: true, + default: true option :bootstrap_protocol, - :long => "--bootstrap-protocol protocol", - :description => "protocol to bootstrap windows servers. options: winrm/ssh", - :proc => Proc.new { |key| Chef::Config[:knife][:bootstrap_protocol] = key }, - :default => nil + long: "--bootstrap-protocol protocol", + description: "protocol to bootstrap windows servers. options: winrm/ssh", + proc: Proc.new { |key| Chef::Config[:knife][:bootstrap_protocol] = key }, + default: nil option :fqdn, - :long => "--fqdn FQDN", - :description => "Pre-defined FQDN. This is used for Kerberos Authentication purpose only", - :proc => Proc.new { |key| Chef::Config[:knife][:fqdn] = key }, - :default => nil + long: "--fqdn FQDN", + description: "Pre-defined FQDN. This is used for Kerberos Authentication purpose only", + proc: Proc.new { |key| Chef::Config[:knife][:fqdn] = key }, + default: nil option :aws_user_data, - :long => "--user-data USER_DATA_FILE", - :short => "-u USER_DATA_FILE", - :description => "The EC2 User Data file to provision the instance with", - :proc => Proc.new { |m| Chef::Config[:knife][:aws_user_data] = m }, - :default => nil + long: "--user-data USER_DATA_FILE", + short: "-u USER_DATA_FILE", + description: "The EC2 User Data file to provision the instance with", + proc: Proc.new { |m| Chef::Config[:knife][:aws_user_data] = m }, + default: nil option :hint, - :long => "--hint HINT_NAME[=HINT_FILE]", - :description => "Specify Ohai Hint to be set on the bootstrap target. Use multiple --hint options to specify multiple hints.", - :proc => Proc.new { |h| - Chef::Config[:knife][:hints] ||= {} - name, path = h.split("=") - Chef::Config[:knife][:hints][name] = path ? JSON.parse(::File.read(path)) : Hash.new + long: "--hint HINT_NAME[=HINT_FILE]", + description: "Specify Ohai Hint to be set on the bootstrap target. Use multiple --hint options to specify multiple hints.", + proc: Proc.new { |h| + Chef::Config[:knife][:hints] ||= {} + name, path = h.split("=") + Chef::Config[:knife][:hints][name] = path ? JSON.parse(::File.read(path)) : Hash.new } option :ephemeral, - :long => "--ephemeral EPHEMERAL_DEVICES", - :description => "Comma separated list of device locations (eg - /dev/sdb) to map ephemeral devices", - :proc => lambda { |o| o.split(/[\s,]+/) }, - :default => [] + long: "--ephemeral EPHEMERAL_DEVICES", + description: "Comma separated list of device locations (eg - /dev/sdb) to map ephemeral devices", + proc: lambda { |o| o.split(/[\s,]+/) }, + default: [] option :server_connect_attribute, - :long => "--server-connect-attribute ATTRIBUTE", - :short => "-a ATTRIBUTE", - :description => "The EC2 server attribute to use for the SSH connection if necessary, e.g. public_ip_address or private_ip_address.", - :default => nil + long: "--server-connect-attribute ATTRIBUTE", + short: "-a ATTRIBUTE", + description: "The EC2 server attribute to use for the SSH connection if necessary, e.g. public_ip_address or private_ip_address.", + default: nil option :associate_public_ip, - :long => "--associate-public-ip", - :description => "Associate public ip to VPC instance.", - :boolean => true, - :default => false + long: "--associate-public-ip", + description: "Associate public ip to VPC instance.", + boolean: true, + default: false option :ebs_volume_type, - :long => "--ebs-volume-type TYPE", - :description => "Possible values are standard (magnetic) | io1 | gp2 | sc1 | st1. Default is gp2", - :proc => Proc.new { |key| Chef::Config[:knife][:ebs_volume_type] = key }, - :default => "gp2" + long: "--ebs-volume-type TYPE", + description: "Possible values are standard (magnetic) | io1 | gp2 | sc1 | st1. Default is gp2", + proc: Proc.new { |key| Chef::Config[:knife][:ebs_volume_type] = key }, + default: "gp2" option :ebs_provisioned_iops, - :long => "--provisioned-iops IOPS", - :description => "IOPS rate, only used when ebs volume type is 'io1'", - :proc => Proc.new { |key| Chef::Config[:knife][:provisioned_iops] = key }, - :default => nil + long: "--provisioned-iops IOPS", + description: "IOPS rate, only used when ebs volume type is 'io1'", + proc: Proc.new { |key| Chef::Config[:knife][:provisioned_iops] = key }, + default: nil option :auth_timeout, - :long => "--windows-auth-timeout MINUTES", - :description => "The maximum time in minutes to wait to for authentication over the transport to the node to succeed. The default value is 25 minutes.", - :default => 25 + long: "--windows-auth-timeout MINUTES", + description: "The maximum time in minutes to wait to for authentication over the transport to the node to succeed. The default value is 25 minutes.", + default: 25 option :validation_key_url, - :long => "--validation-key-url URL", - :description => "Path to the validation key", - :proc => proc { |m| Chef::Config[:validation_key_url] = m } + long: "--validation-key-url URL", + description: "Path to the validation key", + proc: proc { |m| Chef::Config[:validation_key_url] = m } option :ebs_encrypted, - :long => "--ebs-encrypted", - :description => "Enables EBS volume encryption", - :boolean => true, - :default => false + long: "--ebs-encrypted", + description: "Enables EBS volume encryption", + boolean: true, + default: false option :spot_price, - :long => "--spot-price PRICE", - :description => "The maximum hourly USD price for the instance", - :default => nil + long: "--spot-price PRICE", + description: "The maximum hourly USD price for the instance", + default: nil option :spot_request_type, - :long => "--spot-request-type TYPE", - :description => "The Spot Instance request type. Possible values are 'one-time' and 'persistent', default value is 'one-time'", - :default => "one-time" + long: "--spot-request-type TYPE", + description: "The Spot Instance request type. Possible values are 'one-time' and 'persistent', default value is 'one-time'", + default: "one-time" option :spot_wait_mode, - :long => "--spot-wait-mode MODE", - :description => - "Whether we should wait for spot request fulfillment. Could be 'wait', 'exit', or " \ + long: "--spot-wait-mode MODE", + description: "Whether we should wait for spot request fulfillment. Could be 'wait', 'exit', or " \ "'prompt' (default). For any of the above mentioned choices, ('wait') - if the " \ "instance does not get allocated before the command itself times-out or ('exit') the " \ "user needs to manually bootstrap the instance in the future after it gets allocated.", - :default => "prompt" + default: "prompt" option :aws_connection_timeout, - :long => "--aws-connection-timeout MINUTES", - :description => "The maximum time in minutes to wait to for aws connection. Default is 10 min", - :proc => proc {|t| t = t.to_i * 60; Chef::Config[:aws_connection_timeout] = t}, - :default => 600 + long: "--aws-connection-timeout MINUTES", + description: "The maximum time in minutes to wait to for aws connection. Default is 10 min", + proc: proc { |t| t = t.to_i * 60; Chef::Config[:aws_connection_timeout] = t }, + default: 600 option :node_ssl_verify_mode, - :long => "--node-ssl-verify-mode [peer|none]", - :description => "Whether or not to verify the SSL cert for all HTTPS requests.", - :proc => Proc.new { |v| - valid_values = ["none", "peer"] + long: "--node-ssl-verify-mode [peer|none]", + description: "Whether or not to verify the SSL cert for all HTTPS requests.", + proc: Proc.new { |v| + valid_values = %w{none peer} unless valid_values.include?(v) raise "Invalid value '#{v}' for --node-ssl-verify-mode. Valid values are: #{valid_values.join(", ")}" end } option :node_verify_api_cert, - :long => "--[no-]node-verify-api-cert", - :description => "Verify the SSL cert for HTTPS requests to the Chef server API.", - :boolean => true + long: "--[no-]node-verify-api-cert", + description: "Verify the SSL cert for HTTPS requests to the Chef server API.", + boolean: true option :bootstrap_no_proxy, - :long => "--bootstrap-no-proxy [NO_PROXY_URL|NO_PROXY_IP]", - :description => "Do not proxy locations for the node being bootstrapped; this option is used internally by Opscode", - :proc => Proc.new { |np| Chef::Config[:knife][:bootstrap_no_proxy] = np } + long: "--bootstrap-no-proxy [NO_PROXY_URL|NO_PROXY_IP]", + description: "Do not proxy locations for the node being bootstrapped; this option is used internally by Opscode", + proc: Proc.new { |np| Chef::Config[:knife][:bootstrap_no_proxy] = np } option :bootstrap_url, - :long => "--bootstrap-url URL", - :description => "URL to a custom installation script", - :proc => Proc.new { |u| Chef::Config[:knife][:bootstrap_url] = u } + long: "--bootstrap-url URL", + description: "URL to a custom installation script", + proc: Proc.new { |u| Chef::Config[:knife][:bootstrap_url] = u } option :bootstrap_install_command, - :long => "--bootstrap-install-command COMMANDS", - :description => "Custom command to install chef-client", - :proc => Proc.new { |ic| Chef::Config[:knife][:bootstrap_install_command] = ic } + long: "--bootstrap-install-command COMMANDS", + description: "Custom command to install chef-client", + proc: Proc.new { |ic| Chef::Config[:knife][:bootstrap_install_command] = ic } option :bootstrap_wget_options, - :long => "--bootstrap-wget-options OPTIONS", - :description => "Add options to wget when installing chef-client", - :proc => Proc.new { |wo| Chef::Config[:knife][:bootstrap_wget_options] = wo } + long: "--bootstrap-wget-options OPTIONS", + description: "Add options to wget when installing chef-client", + proc: Proc.new { |wo| Chef::Config[:knife][:bootstrap_wget_options] = wo } option :bootstrap_curl_options, - :long => "--bootstrap-curl-options OPTIONS", - :description => "Add options to curl when install chef-client", - :proc => Proc.new { |co| Chef::Config[:knife][:bootstrap_curl_options] = co } + long: "--bootstrap-curl-options OPTIONS", + description: "Add options to curl when install chef-client", + proc: Proc.new { |co| Chef::Config[:knife][:bootstrap_curl_options] = co } option :bootstrap_vault_file, - :long => '--bootstrap-vault-file VAULT_FILE', - :description => 'A JSON file with a list of vault(s) and item(s) to be updated' + long: "--bootstrap-vault-file VAULT_FILE", + description: "A JSON file with a list of vault(s) and item(s) to be updated" option :bootstrap_vault_json, - :long => '--bootstrap-vault-json VAULT_JSON', - :description => 'A JSON string with the vault(s) and item(s) to be updated' + long: "--bootstrap-vault-json VAULT_JSON", + description: "A JSON string with the vault(s) and item(s) to be updated" option :bootstrap_vault_item, - :long => '--bootstrap-vault-item VAULT_ITEM', - :description => 'A single vault and item to update as "vault:item"', - :proc => Proc.new { |i| + long: "--bootstrap-vault-item VAULT_ITEM", + description: 'A single vault and item to update as "vault:item"', + proc: Proc.new { |i| (vault, item) = i.split(/:/) Chef::Config[:knife][:bootstrap_vault_item] ||= {} Chef::Config[:knife][:bootstrap_vault_item][vault] ||= [] Chef::Config[:knife][:bootstrap_vault_item][vault].push(item) Chef::Config[:knife][:bootstrap_vault_item] } option :use_sudo_password, - :long => "--use-sudo-password", - :description => "Execute the bootstrap via sudo with password", - :boolean => false + long: "--use-sudo-password", + description: "Execute the bootstrap via sudo with password", + boolean: false option :forward_agent, - :short => "-A", - :long => "--forward-agent", - :description => "Enable SSH agent forwarding", - :boolean => true + short: "-A", + long: "--forward-agent", + description: "Enable SSH agent forwarding", + boolean: true option :create_ssl_listener, - :long => "--[no-]create-ssl-listener", - :description => "Create ssl listener, enabled by default.", - :boolean => true, - :default => true + long: "--[no-]create-ssl-listener", + description: "Create ssl listener, enabled by default.", + boolean: true, + default: true option :network_interfaces, - :short => '-n', - :long => '--attach-network-interface ENI1,ENI2', - :description => 'Attach additional network interfaces during bootstrap', - :proc => proc { |nics| nics.split(',') } + short: "-n", + long: "--attach-network-interface ENI1,ENI2", + description: "Attach additional network interfaces during bootstrap", + proc: proc { |nics| nics.split(",") } option :classic_link_vpc_id, - :long => "--classic-link-vpc-id VPC_ID", - :description => "Enable ClassicLink connection with a VPC" + long: "--classic-link-vpc-id VPC_ID", + description: "Enable ClassicLink connection with a VPC" option :classic_link_vpc_security_group_ids, - :long => "--classic-link-vpc-security-groups-ids X,Y,Z", - :description => "Comma-separated list of security group ids for ClassicLink", - :proc => Proc.new { |groups| groups.split(',') } + long: "--classic-link-vpc-security-groups-ids X,Y,Z", + description: "Comma-separated list of security group ids for ClassicLink", + proc: Proc.new { |groups| groups.split(",") } option :disable_api_termination, - :long => "--disable-api-termination", - :description => "Disable termination of the instance using the Amazon EC2 console, CLI and API.", - :boolean => true, - :default => false + long: "--disable-api-termination", + description: "Disable termination of the instance using the Amazon EC2 console, CLI and API.", + boolean: true, + default: false option :volume_tags, - :long => "--volume-tags Tag=Value[,Tag=Value...]", - :description => "Tag the Root volume", - :proc => Proc.new { |volume_tags| volume_tags.split(',') } + long: "--volume-tags Tag=Value[,Tag=Value...]", + description: "Tag the Root volume", + proc: Proc.new { |volume_tags| volume_tags.split(",") } option :tag_node_in_chef, - :long => "--tag-node-in-chef", - :description => "Flag for tagging node in ec2 and chef both. [DEPRECATED] Use --chef-tag instead.", - :proc => Proc.new { |v| + long: "--tag-node-in-chef", + description: "Flag for tagging node in ec2 and chef both. [DEPRECATED] Use --chef-tag instead.", + proc: Proc.new { |v| Chef::Log.warn("[DEPRECATED] --tag-node-in-chef option is deprecated. Use --chef-tag option instead.") v }, - :boolean => true, - :default => false + boolean: true, + default: false option :instance_initiated_shutdown_behavior, - :long => "--instance-initiated-shutdown-behavior SHUTDOWN_BEHAVIOR", - :description => "Indicates whether an instance stops or terminates when you initiate shutdown from the instance. Possible values are 'stop' and 'terminate', default is 'stop'." + long: "--instance-initiated-shutdown-behavior SHUTDOWN_BEHAVIOR", + description: "Indicates whether an instance stops or terminates when you initiate shutdown from the instance. Possible values are 'stop' and 'terminate', default is 'stop'." option :chef_tag, - :long => "--chef-tag CHEF_TAG", - :description => "Use to tag the node in chef server; Provide --chef-tag option multiple times when specifying multiple tags e.g. --chef-tag tag1 --chef-tag tag2.", - :proc => Proc.new { |chef_tag| + long: "--chef-tag CHEF_TAG", + description: "Use to tag the node in chef server; Provide --chef-tag option multiple times when specifying multiple tags e.g. --chef-tag tag1 --chef-tag tag2.", + proc: Proc.new { |chef_tag| Chef::Config[:knife][:chef_tag] ||= [] Chef::Config[:knife][:chef_tag].push(chef_tag) Chef::Config[:knife][:chef_tag] } option :aws_tag, - :long => "--aws-tag AWS_TAG", - :description => "AWS tag for this server; Use the --aws-tag option multiple times when specifying multiple tags e.g. --aws-tag key1=value1 --aws-tag key2=value2.", - :proc => Proc.new { |aws_tag| + long: "--aws-tag AWS_TAG", + description: "AWS tag for this server; Use the --aws-tag option multiple times when specifying multiple tags e.g. --aws-tag key1=value1 --aws-tag key2=value2.", + proc: Proc.new { |aws_tag| Chef::Config[:knife][:aws_tag] ||= [] Chef::Config[:knife][:aws_tag].push(aws_tag) Chef::Config[:knife][:aws_tag] } @@ -491,31 +470,31 @@ validate! requested_elastic_ip = config[:associate_eip] if config[:associate_eip] # For VPC EIP assignment we need the allocation ID so fetch full EIP details - elastic_ip = connection.addresses.detect{|addr| addr if addr.public_ip == requested_elastic_ip} + elastic_ip = connection.addresses.detect { |addr| addr if addr.public_ip == requested_elastic_ip } if locate_config_value(:spot_price) server_def = create_server_def server_def[:groups] = server_def[:security_group_ids] if vpc_mode? spot_request = connection.spot_requests.create(server_def) msg_pair("Spot Request ID", spot_request.id) msg_pair("Spot Request Type", spot_request.request_type) msg_pair("Spot Price", spot_request.price) case config[:spot_wait_mode] - when 'prompt', '', nil + when "prompt", "", nil wait_msg = "Do you want to wait for Spot Instance Request fulfillment? (Y/N) \n" wait_msg += "Y - Wait for Spot Instance request fulfillment\n" wait_msg += "N - Do not wait for Spot Instance request fulfillment. " wait_msg += ui.color("[WARN :: Request would be alive on AWS ec2 side but execution of Chef Bootstrap on the target instance will get skipped.]\n", :red, :bold) wait_msg += ui.color("\n[WARN :: For any of the above mentioned choices, (Y) - if the instance does not get allocated before the command itself times-out or (N) - user decides to exit, then in both cases user needs to manually bootstrap the instance in the future after it gets allocated.]\n\n", :cyan, :bold) confirm(wait_msg) - when 'wait' + when "wait" # wait for the node and run Chef bootstrap - when 'exit' + when "exit" ui.color("The 'exit' option was specified for --spot-wait-mode, exiting.", :cyan) exit else raise "Invalid value for --spot-wait-mode: '#{config[:spot_wait_mode]}', " \ "valid values: wait, exit, prompt" @@ -538,28 +517,28 @@ Chef::Log.debug("#{error.backtrace.join("\n")}") exit end end - hashed_tags={} - tags.map{ |t| key,val=t.split('='); hashed_tags[key]=val} unless tags.nil? + hashed_tags = {} + tags.map { |t| key, val = t.split("="); hashed_tags[key] = val } unless tags.nil? # Always set the Name tag unless hashed_tags.keys.include? "Name" if locate_config_value(:chef_node_name) hashed_tags["Name"] = evaluate_node_name(locate_config_value(:chef_node_name)) else hashed_tags["Name"] = server.id end end - printed_aws_tags = hashed_tags.map{ |tag, val| "#{tag}: #{val}" }.join(", ") + printed_aws_tags = hashed_tags.map { |tag, val| "#{tag}: #{val}" }.join(", ") - hashed_volume_tags={} + hashed_volume_tags = {} volume_tags = locate_config_value(:volume_tags) - volume_tags.map{ |t| key,val=t.split('='); hashed_volume_tags[key]=val} unless volume_tags.nil? - printed_volume_tags = hashed_volume_tags.map{ |tag, val| "#{tag}: #{val}" }.join(", ") + volume_tags.map { |t| key, val = t.split("="); hashed_volume_tags[key] = val } unless volume_tags.nil? + printed_volume_tags = hashed_volume_tags.map { |tag, val| "#{tag}: #{val}" }.join(", ") msg_pair("Instance ID", @server.id) msg_pair("Flavor", @server.flavor_id) msg_pair("Image", @server.image_id) msg_pair("Region", connection.instance_variable_get(:@region)) @@ -569,15 +548,15 @@ # pick the appropriate default one. In case of a VPC we don't know the # default security group id at this point unless we look it up, hence # 'default' is printed if no id was specified. printed_security_groups = "default" printed_security_groups = @server.groups.join(", ") if @server.groups - msg_pair("Security Groups", printed_security_groups) unless vpc_mode? or (@server.groups.nil? and @server.security_group_ids) + msg_pair("Security Groups", printed_security_groups) unless vpc_mode? || (@server.groups.nil? && @server.security_group_ids) printed_security_group_ids = "default" printed_security_group_ids = @server.security_group_ids.join(", ") if @server.security_group_ids - msg_pair("Security Group Ids", printed_security_group_ids) if vpc_mode? or @server.security_group_ids + msg_pair("Security Group Ids", printed_security_group_ids) if vpc_mode? || @server.security_group_ids msg_pair("IAM Profile", locate_config_value(:iam_instance_profile)) msg_pair("AWS Tags", printed_aws_tags) msg_pair("Volume Tags", printed_volume_tags) @@ -625,28 +604,28 @@ if Chef::Config[:knife][:validation_key_url] download_validation_key(validation_key_path) Chef::Config[:validation_key] = validation_key_path end - #Check if Server is Windows or Linux + # Check if Server is Windows or Linux if is_image_windows? protocol = locate_config_value(:bootstrap_protocol) - protocol ||= 'winrm' - if protocol == 'winrm' + protocol ||= "winrm" + if protocol == "winrm" load_winrm_deps print "\n#{ui.color("Waiting for winrm access to become available", :magenta)}" - print(".") until tcp_test_winrm(ssh_connect_host, locate_config_value(:winrm_port)) { + print(".") until tcp_test_winrm(ssh_connect_host, locate_config_value(:winrm_port)) do sleep 10 puts("done") - } + end else print "\n#{ui.color("Waiting for sshd access to become available", :magenta)}" - #If FreeSSHd, winsshd etc are available - print(".") until tcp_test_ssh(ssh_connect_host, config[:ssh_port]) { + # If FreeSSHd, winsshd etc are available + print(".") until tcp_test_ssh(ssh_connect_host, config[:ssh_port]) do sleep @initial_sleep_delay ||= (vpc_mode? ? 40 : 10) puts("done") - } + end ssh_override_winrm end bootstrap_for_windows_node(@server, ssh_connect_host).run else print "\n#{ui.color("Waiting for sshd access to become available", :magenta)}" @@ -660,45 +639,45 @@ msg_pair("Flavor", @server.flavor_id) msg_pair("Placement Group", @server.placement_group) unless @server.placement_group.nil? msg_pair("Image", @server.image_id) msg_pair("Region", connection.instance_variable_get(:@region)) msg_pair("Availability Zone", @server.availability_zone) - msg_pair("Security Groups", printed_security_groups) unless vpc_mode? or (@server.groups.nil? and @server.security_group_ids) - msg_pair("Security Group Ids", printed_security_group_ids) if vpc_mode? or @server.security_group_ids + msg_pair("Security Groups", printed_security_groups) unless vpc_mode? || (@server.groups.nil? && @server.security_group_ids) + msg_pair("Security Group Ids", printed_security_group_ids) if vpc_mode? || @server.security_group_ids msg_pair("IAM Profile", locate_config_value(:iam_instance_profile)) if locate_config_value(:iam_instance_profile) msg_pair("Primary ENI", locate_config_value(:primary_eni)) if locate_config_value(:primary_eni) msg_pair("AWS Tags", printed_aws_tags) msg_pair("Chef Tags", locate_config_value(:chef_tag)) if locate_config_value(:chef_tag) msg_pair("SSH Key", @server.key_name) msg_pair("Root Device Type", @server.root_device_type) msg_pair("Root Volume Tags", printed_volume_tags) if @server.root_device_type == "ebs" device_map = @server.block_device_mapping.first - msg_pair("Root Volume ID", device_map['volumeId']) - msg_pair("Root Device Name", device_map['deviceName']) - msg_pair("Root Device Delete on Terminate", device_map['deleteOnTermination']) - msg_pair("Standard or Provisioned IOPS", device_map['volumeType']) - msg_pair("IOPS rate", device_map['iops']) + msg_pair("Root Volume ID", device_map["volumeId"]) + msg_pair("Root Device Name", device_map["deviceName"]) + msg_pair("Root Device Delete on Terminate", device_map["deleteOnTermination"]) + msg_pair("Standard or Provisioned IOPS", device_map["volumeType"]) + msg_pair("IOPS rate", device_map["iops"]) print "\n#{ui.color("Block devices", :magenta)}\n" print "#{ui.color("===========================", :magenta)}\n" @server.block_device_mapping.each do |device_map| - msg_pair("Device Name", device_map['deviceName']) - msg_pair("Volume ID", device_map['volumeId']) - msg_pair("Delete on Terminate", device_map['deleteOnTermination'].to_s) - msg_pair("Standard or Provisioned IOPS", device_map['volumeType']) - msg_pair("IOPS rate", device_map['iops']) + msg_pair("Device Name", device_map["deviceName"]) + msg_pair("Volume ID", device_map["volumeId"]) + msg_pair("Delete on Terminate", device_map["deleteOnTermination"].to_s) + msg_pair("Standard or Provisioned IOPS", device_map["volumeType"]) + msg_pair("IOPS rate", device_map["iops"]) print "\n" end print "#{ui.color("===========================", :magenta)}\n" if config[:ebs_size] - if ami.block_device_mapping.first['volumeSize'].to_i < config[:ebs_size].to_i + if ami.block_device_mapping.first["volumeSize"].to_i < config[:ebs_size].to_i volume_too_large_warning = "#{config[:ebs_size]}GB " + - "EBS volume size is larger than size set in AMI of " + - "#{ami.block_device_mapping.first['volumeSize']}GB.\n" + - "Use file system tools to make use of the increased volume size." + "EBS volume size is larger than size set in AMI of " + + "#{ami.block_device_mapping.first['volumeSize']}GB.\n" + + "Use file system tools to make use of the increased volume size." msg_pair("Warning", volume_too_large_warning, :yellow) end end end if config[:ebs_optimized] @@ -714,43 +693,46 @@ msg_pair("Public DNS Name", @server.dns_name) msg_pair("Public IP Address", @server.public_ip_address) msg_pair("Private DNS Name", @server.private_dns_name) end msg_pair("Private IP Address", @server.private_ip_address) - msg_pair("Environment", config[:environment] || '_default') - msg_pair("Run List", (config[:run_list] || []).join(', ')) + msg_pair("Environment", config[:environment] || "_default") + msg_pair("Run List", (config[:run_list] || []).join(", ")) if config[:first_boot_attributes] || config[:first_boot_attributes_from_file] - msg_pair("JSON Attributes",config[:first_boot_attributes] || config[:first_boot_attributes_from_file]) + msg_pair("JSON Attributes", config[:first_boot_attributes] || config[:first_boot_attributes_from_file]) end end + # return the default bootstrap template based on platform + # @return [String] def default_bootstrap_template - is_image_windows? ? 'windows-chef-client-msi' : 'chef-full' + is_image_windows? ? "windows-chef-client-msi" : "chef-full" end def validation_key_path @validation_key_path ||= begin - if URI(Chef::Config[:knife][:validation_key_url]).scheme == 'file' + if URI(Chef::Config[:knife][:validation_key_url]).scheme == "file" URI(Chef::Config[:knife][:validation_key_url]).path else validation_key_tmpfile.path end end end + # @return [Tempfile] def validation_key_tmpfile - @validation_key_tmpfile ||= Tempfile.new('validation_key') + @validation_key_tmpfile ||= Tempfile.new("validation_key") end def download_validation_key(tempfile) - Chef::Log.debug 'Downloading validation key ' \ + Chef::Log.debug "Downloading validation key " \ "<#{Chef::Config[:knife][:validation_key_url]}> to file " \ "<#{tempfile}>" case URI(Chef::Config[:knife][:validation_key_url]).scheme - when 's3' - File.open(tempfile, 'w') { |f| f.write(s3_validation_key) } + when "s3" + File.open(tempfile, "w") { |f| f.write(s3_validation_key) } end end def s3_validation_key @s3_validation_key ||= begin @@ -768,13 +750,10 @@ def bootstrap_common_params(bootstrap) bootstrap.config[:run_list] = config[:run_list] bootstrap.config[:policy_group] = locate_config_value(:policy_group) bootstrap.config[:policy_name] = locate_config_value(:policy_name) bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version) - bootstrap.config[:distro] = locate_config_value(:distro) || default_bootstrap_template - # setting bootstrap_template value to template_file for backward compatibility - bootstrap.config[:template_file] = locate_config_value(:template_file) || locate_config_value(:bootstrap_template) bootstrap.config[:environment] = locate_config_value(:environment) bootstrap.config[:prerelease] = config[:prerelease] bootstrap.config[:first_boot_attributes] = locate_config_value(:first_boot_attributes) bootstrap.config[:first_boot_attributes_from_file] = locate_config_value(:first_boot_attributes_from_file) bootstrap.config[:encrypted_data_bag_secret] = s3_secret || locate_config_value(:secret) @@ -811,18 +790,18 @@ Chef::Config[:knife][:hints]["ec2"] ||= {} bootstrap end def fetch_server_fqdn(ip_addr) - require 'resolv' + require "resolv" Resolv.getname(ip_addr) end def bootstrap_for_windows_node(server, fqdn) - if locate_config_value(:bootstrap_protocol) == 'winrm' || locate_config_value(:bootstrap_protocol) == nil + if locate_config_value(:bootstrap_protocol) == "winrm" || locate_config_value(:bootstrap_protocol).nil? if locate_config_value(:kerberos_realm) - #Fetch AD/WINS based fqdn if any for Kerberos-based Auth + # Fetch AD/WINS based fqdn if any for Kerberos-based Auth fqdn = locate_config_value(:fqdn) || fetch_server_fqdn(server.private_ip_address) end bootstrap = Chef::Knife::BootstrapWindowsWinrm.new bootstrap.config[:winrm_user] = locate_config_value(:winrm_user) bootstrap.config[:winrm_password] = windows_password @@ -832,11 +811,11 @@ bootstrap.config[:kerberos_service] = locate_config_value(:kerberos_service) bootstrap.config[:ca_trust_file] = locate_config_value(:ca_trust_file) bootstrap.config[:winrm_port] = locate_config_value(:winrm_port) bootstrap.config[:auth_timeout] = locate_config_value(:auth_timeout) bootstrap.config[:winrm_ssl_verify_mode] = locate_config_value(:winrm_ssl_verify_mode) - elsif locate_config_value(:bootstrap_protocol) == 'ssh' + elsif locate_config_value(:bootstrap_protocol) == "ssh" bootstrap = Chef::Knife::BootstrapWindowsSsh.new bootstrap.config[:ssh_user] = locate_config_value(:ssh_user) bootstrap.config[:ssh_password] = locate_config_value(:ssh_password) bootstrap.config[:ssh_port] = locate_config_value(:ssh_port) bootstrap.config[:identity_file] = locate_config_value(:identity_file) @@ -857,11 +836,11 @@ bootstrap.config[:chef_node_name] = server.id end bootstrap_common_params(bootstrap) end - def bootstrap_for_linux_node(server,ssh_host) + def bootstrap_for_linux_node(server, ssh_host) bootstrap = Chef::Knife::Bootstrap.new bootstrap.name_args = [ssh_host] bootstrap.config[:ssh_user] = config[:ssh_user] bootstrap.config[:ssh_password] = locate_config_value(:ssh_password) bootstrap.config[:ssh_port] = config[:ssh_port] @@ -871,11 +850,11 @@ if locate_config_value(:chef_node_name) bootstrap.config[:chef_node_name] = evaluate_node_name(locate_config_value(:chef_node_name)) else bootstrap.config[:chef_node_name] = server.id end - bootstrap.config[:use_sudo] = true unless config[:ssh_user] == 'root' + bootstrap.config[:use_sudo] = true unless config[:ssh_user] == "root" # may be needed for vpc_mode bootstrap.config[:host_key_verify] = config[:host_key_verify] bootstrap_common_params(bootstrap) end @@ -899,54 +878,54 @@ super([:image, :ssh_key_name, :aws_access_key_id, :aws_secret_access_key]) validate_nics! if locate_config_value(:network_interfaces) if ami.nil? - ui.error("You have not provided a valid image (AMI) value.") + ui.error("The provided AMI value '#{locate_config_value(:image)}' could not be found. Is this AMI availble in the provided region #{locate_config_value(:region)}?") exit 1 end - if vpc_mode? and !!config[:security_groups] + if vpc_mode? && !!config[:security_groups] ui.error("You are using a VPC, security groups specified with '-G' are not allowed, specify one or more security group ids with '-g' instead.") exit 1 end - if !vpc_mode? and !!config[:private_ip_address] + if !vpc_mode? && !!config[:private_ip_address] ui.error("You can only specify a private IP address if you are using VPC.") exit 1 end - if config[:dedicated_instance] and !vpc_mode? + if config[:dedicated_instance] && !vpc_mode? ui.error("You can only specify a Dedicated Instance if you are using VPC.") exit 1 end - if !vpc_mode? and config[:associate_public_ip] + if !vpc_mode? && config[:associate_public_ip] ui.error("--associate-public-ip option only applies to VPC instances, and you have not specified a subnet id.") exit 1 end if config[:associate_eip] - eips = connection.addresses.collect{|addr| addr if addr.domain == eip_scope}.compact + eips = connection.addresses.collect { |addr| addr if addr.domain == eip_scope }.compact - unless eips.detect{|addr| addr.public_ip == config[:associate_eip] && addr.server_id == nil} + unless eips.detect { |addr| addr.public_ip == config[:associate_eip] && addr.server_id.nil? } ui.error("Elastic IP requested is not available.") exit 1 end end - if config[:ebs_provisioned_iops] and config[:ebs_volume_type] != 'io1' + if config[:ebs_provisioned_iops] && (config[:ebs_volume_type] != "io1") ui.error("--provisioned-iops option is only supported for volume type of 'io1'") exit 1 end - if config[:ebs_volume_type] == 'io1' and config[:ebs_provisioned_iops].nil? + if (config[:ebs_volume_type] == "io1") && config[:ebs_provisioned_iops].nil? ui.error("--provisioned-iops option is required when using volume type of 'io1'") exit 1 end - if config[:ebs_volume_type] and ! %w(gp2 io1 standard).include?(config[:ebs_volume_type]) + if config[:ebs_volume_type] && ! %w{gp2 io1 standard}.include?(config[:ebs_volume_type]) ui.error("--ebs-volume-type must be 'standard' or 'io1' or 'gp2'") msg opt_parser exit 1 end @@ -964,11 +943,11 @@ if config[:classic_link_vpc_id].nil? ^ config[:classic_link_vpc_security_group_ids].nil? ui.error("--classic-link-vpc-id and --classic-link-vpc-security-group-ids must be used together") exit 1 end - if vpc_mode? and config[:classic_link_vpc_id] + if vpc_mode? && config[:classic_link_vpc_id] ui.error("You can only use ClassicLink if you are not using a VPC") exit 1 end if locate_config_value(:ebs_encrypted) @@ -976,65 +955,65 @@ errors = [] # validation for flavor and ebs_encrypted if !locate_config_value(:flavor) ui.error("--ebs-encrypted option requires valid flavor to be specified.") exit 1 - elsif (locate_config_value(:ebs_encrypted) and ! %w(m3.medium m3.large m3.xlarge m3.2xlarge m4.large m4.xlarge + elsif locate_config_value(:ebs_encrypted) && ! %w{m3.medium m3.large m3.xlarge m3.2xlarge m4.large m4.xlarge m4.2xlarge m4.4xlarge m4.10xlarge m4.16xlarge t2.nano t2.micro t2.small - t2.medium t2.large t2.xlarge t2.2xlarge d2.xlarge d2.2xlarge d2.4xlarge + t2.medium t2.large t2.xlarge t2.2xlarge d2.xlarge d2.2xlarge d2.4xlarge d2.8xlarge c4.large c4.xlarge c4.2xlarge c4.4xlarge c4.8xlarge c3.large c3.xlarge c3.2xlarge c3.4xlarge c3.8xlarge cr1.8xlarge r3.large r3.xlarge r3.2xlarge r3.4xlarge r3.8xlarge r4.large r4.xlarge r4.2xlarge r4.4xlarge r4.8xlarge r4.16xlarge x1.16xlarge x1.32xlarge i2.xlarge i2.2xlarge i2.4xlarge i2.8xlarge i3.large i3.xlarge i3.2xlarge i3.4xlarge i3.8xlarge i3.16xlarge - f1.2xlarge f1.16xlarge g2.2xlarge g2.8xlarge p2.xlarge p2.8xlarge p2.16xlarge).include?(locate_config_value(:flavor))) + f1.2xlarge f1.16xlarge g2.2xlarge g2.8xlarge p2.xlarge p2.8xlarge p2.16xlarge}.include?(locate_config_value(:flavor)) ui.error("--ebs-encrypted option is not supported for #{locate_config_value(:flavor)} flavor.") exit 1 end # validation for ebs_size and ebs_volume_type and ebs_encrypted if !locate_config_value(:ebs_size) errors << "--ebs-encrypted option requires valid --ebs-size to be specified." - elsif locate_config_value(:ebs_volume_type) == "gp2" and ! locate_config_value(:ebs_size).to_i.between?(1, 16384) + elsif (locate_config_value(:ebs_volume_type) == "gp2") && ! locate_config_value(:ebs_size).to_i.between?(1, 16384) errors << "--ebs-size should be in between 1-16384 for 'gp2' ebs volume type." - elsif locate_config_value(:ebs_volume_type) == "io1" and ! locate_config_value(:ebs_size).to_i.between?(4, 16384) + elsif (locate_config_value(:ebs_volume_type) == "io1") && ! locate_config_value(:ebs_size).to_i.between?(4, 16384) errors << "--ebs-size should be in between 4-16384 for 'io1' ebs volume type." - elsif locate_config_value(:ebs_volume_type) == "standard" and ! locate_config_value(:ebs_size).to_i.between?(1, 1024) + elsif (locate_config_value(:ebs_volume_type) == "standard") && ! locate_config_value(:ebs_size).to_i.between?(1, 1024) errors << "--ebs-size should be in between 1-1024 for 'standard' ebs volume type." end - if errors.each{|e| error_message = "#{error_message} #{e}"}.any? + if errors.each { |e| error_message = "#{error_message} #{e}" }.any? ui.error(error_message) exit 1 end end if locate_config_value(:spot_price) && locate_config_value(:disable_api_termination) ui.error("spot-price and disable-api-termination options cannot be passed together as 'Termination Protection' cannot be enabled for spot instances.") exit 1 end - if locate_config_value(:spot_price).nil? && locate_config_value(:spot_wait_mode).downcase != 'prompt' - ui.error('spot-wait-mode option requires that a spot-price option is set.') + if locate_config_value(:spot_price).nil? && !locate_config_value(:spot_wait_mode).casecmp("prompt").zero? + ui.error("spot-wait-mode option requires that a spot-price option is set.") exit 1 end volume_tags = locate_config_value(:volume_tags) - if !volume_tags.nil? and volume_tags.length != volume_tags.to_s.count('=') + if !volume_tags.nil? && (volume_tags.length != volume_tags.to_s.count("=")) ui.error("Volume Tags should be entered in a key = value pair") exit 1 end - if (locate_config_value(:winrm_password).to_s.length > 14 ) + if locate_config_value(:winrm_password).to_s.length > 14 ui.warn("The password provided is longer than 14 characters. Computers with Windows prior to Windows 2000 will not be able to use this account. Do you want to continue this operation? (Y/N):") password_promt = STDIN.gets.chomp.upcase - if (password_promt == "N") - raise "Exiting as operation with password greater than 14 characters not accepted" - elsif (password_promt == "Y") - @allow_long_password = "/yes" + if password_promt == "N" + raise "Exiting as operation with password greater than 14 characters not accepted" + elsif password_promt == "Y" + @allow_long_password = "/yes" else - raise "The input provided is incorrect." + raise "The input provided is incorrect." end end if locate_config_value(:tag_node_in_chef) ui.warn("[DEPRECATED] --tag-node-in-chef option is deprecated. Use --chef-tag option instead.") @@ -1044,16 +1023,16 @@ ui.warn("[DEPRECATED] --tags option is deprecated. Use --aws-tag option instead.") end end def tags - tags = locate_config_value(:tags) || locate_config_value(:aws_tag) - if !tags.nil? and tags.length != tags.to_s.count('=') + tags = locate_config_value(:tags) || locate_config_value(:aws_tag) + if !tags.nil? && (tags.length != tags.to_s.count("=")) ui.error("AWS Tags should be entered in a key = value pair") exit 1 end - tags + tags end def eip_scope if vpc_mode? "vpc" @@ -1061,68 +1040,68 @@ "standard" end end def ssl_config_user_data - user_related_commands = "" - winrm_user = locate_config_value(:winrm_user).split("\\") - if (winrm_user[0] == ".") || (winrm_user[0] == "") ||(winrm_user.length == 1) - user_related_commands = <<-EOH -net user /add #{locate_config_value(:winrm_user).delete('.\\')} #{windows_password} #{@allow_long_password}; -net localgroup Administrators /add #{locate_config_value(:winrm_user).delete('.\\')}; + user_related_commands = "" + winrm_user = locate_config_value(:winrm_user).split("\\") + if (winrm_user[0] == ".") || (winrm_user[0] == "") || (winrm_user.length == 1) + user_related_commands = <<~EOH + net user /add #{locate_config_value(:winrm_user).delete('.\\')} #{windows_password} #{@allow_long_password}; + net localgroup Administrators /add #{locate_config_value(:winrm_user).delete('.\\')}; EOH - end -<<-EOH -#{user_related_commands} -If (-Not (Get-Service WinRM | Where-Object {$_.status -eq "Running"})) { - winrm quickconfig -q -} -If (winrm e winrm/config/listener | Select-String -Pattern " Transport = HTTP\\b" -Quiet) { - winrm delete winrm/config/listener?Address=*+Transport=HTTP -} -$vm_name = invoke-restmethod -uri http://169.254.169.254/latest/meta-data/public-ipv4 -If (-Not $vm_name) { - $vm_name = invoke-restmethod -uri http://169.254.169.254/latest/meta-data/local-ipv4 -} + end + <<~EOH + #{user_related_commands} + If (-Not (Get-Service WinRM | Where-Object {$_.status -eq "Running"})) { + winrm quickconfig -q + } + If (winrm e winrm/config/listener | Select-String -Pattern " Transport = HTTP\\b" -Quiet) { + winrm delete winrm/config/listener?Address=*+Transport=HTTP + } + $vm_name = invoke-restmethod -uri http://169.254.169.254/latest/meta-data/public-ipv4 + If (-Not $vm_name) { + $vm_name = invoke-restmethod -uri http://169.254.169.254/latest/meta-data/local-ipv4 + } -$name = new-object -com "X509Enrollment.CX500DistinguishedName.1" -$name.Encode("CN=$vm_name", 0) -$key = new-object -com "X509Enrollment.CX509PrivateKey.1" -$key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider" -$key.KeySpec = 1 -$key.Length = 2048 -$key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)" -$key.MachineContext = 1 -$key.Create() -$serverauthoid = new-object -com "X509Enrollment.CObjectId.1" -$serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1") -$ekuoids = new-object -com "X509Enrollment.CObjectIds.1" -$ekuoids.add($serverauthoid) -$ekuext = new-object -com "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1" -$ekuext.InitializeEncode($ekuoids) -$cert = new-object -com "X509Enrollment.CX509CertificateRequestCertificate.1" -$cert.InitializeFromPrivateKey(2, $key, "") -$cert.Subject = $name -$cert.Issuer = $cert.Subject -$cert.NotBefore = get-date -$cert.NotAfter = $cert.NotBefore.AddYears(10) -$cert.X509Extensions.Add($ekuext) -$cert.Encode() -$enrollment = new-object -com "X509Enrollment.CX509Enrollment.1" -$enrollment.InitializeFromRequest($cert) -$certdata = $enrollment.CreateRequest(0) -$enrollment.InstallResponse(2, $certdata, 0, "") + $name = new-object -com "X509Enrollment.CX500DistinguishedName.1" + $name.Encode("CN=$vm_name", 0) + $key = new-object -com "X509Enrollment.CX509PrivateKey.1" + $key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider" + $key.KeySpec = 1 + $key.Length = 2048 + $key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)" + $key.MachineContext = 1 + $key.Create() + $serverauthoid = new-object -com "X509Enrollment.CObjectId.1" + $serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1") + $ekuoids = new-object -com "X509Enrollment.CObjectIds.1" + $ekuoids.add($serverauthoid) + $ekuext = new-object -com "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1" + $ekuext.InitializeEncode($ekuoids) + $cert = new-object -com "X509Enrollment.CX509CertificateRequestCertificate.1" + $cert.InitializeFromPrivateKey(2, $key, "") + $cert.Subject = $name + $cert.Issuer = $cert.Subject + $cert.NotBefore = get-date + $cert.NotAfter = $cert.NotBefore.AddYears(10) + $cert.X509Extensions.Add($ekuext) + $cert.Encode() + $enrollment = new-object -com "X509Enrollment.CX509Enrollment.1" + $enrollment.InitializeFromRequest($cert) + $certdata = $enrollment.CreateRequest(0) + $enrollment.InstallResponse(2, $certdata, 0, "") -$thumbprint = (Get-ChildItem -Path cert:\\localmachine\\my | Where-Object {$_.Subject -match "$vm_name"}).Thumbprint; -$create_listener_cmd = "winrm create winrm/config/Listener?Address=*+Transport=HTTPS '@{Hostname=`"$vm_name`";CertificateThumbprint=`"$thumbprint`"}'" -iex $create_listener_cmd -netsh advfirewall firewall add rule name="WinRM HTTPS" protocol=TCP dir=in Localport=5986 remoteport=any action=allow localip=any remoteip=any profile=any enable=yes + $thumbprint = (Get-ChildItem -Path cert:\\localmachine\\my | Where-Object {$_.Subject -match "$vm_name"}).Thumbprint; + $create_listener_cmd = "winrm create winrm/config/Listener?Address=*+Transport=HTTPS '@{Hostname=`"$vm_name`";CertificateThumbprint=`"$thumbprint`"}'" + iex $create_listener_cmd + netsh advfirewall firewall add rule name="WinRM HTTPS" protocol=TCP dir=in Localport=5986 remoteport=any action=allow localip=any remoteip=any profile=any enable=yes EOH end def ssl_config_data_already_exist? - File.read(locate_config_value(:aws_user_data)).gsub(/\\\\/,"\\").include? ssl_config_user_data.strip + File.read(locate_config_value(:aws_user_data)).gsub(/\\\\/, "\\").include? ssl_config_user_data.strip end def process_user_data(script_lines) if !ssl_config_data_already_exist? ps_start_tag = "<powershell>\n" @@ -1134,66 +1113,66 @@ ui.error("Provided user_data file is invalid.") exit 1 when ps_start_tag_index && ps_end_tag_index script_lines[ps_end_tag_index] = ssl_config_user_data + ps_end_tag when !ps_start_tag_index && !ps_end_tag_index - script_lines.insert(-1,"\n\n" + ps_start_tag + ssl_config_user_data + ps_end_tag) + script_lines.insert(-1, "\n\n" + ps_start_tag + ssl_config_user_data + ps_end_tag) end end script_lines end def create_server_def server_def = { - :image_id => locate_config_value(:image), - :groups => config[:security_groups], - :flavor_id => locate_config_value(:flavor), - :key_name => locate_config_value(:ssh_key_name), - :availability_zone => locate_config_value(:availability_zone), - :price => locate_config_value(:spot_price), - :request_type => locate_config_value(:spot_request_type) + image_id: locate_config_value(:image), + groups: config[:security_groups], + flavor_id: locate_config_value(:flavor), + key_name: locate_config_value(:ssh_key_name), + availability_zone: locate_config_value(:availability_zone), + price: locate_config_value(:spot_price), + request_type: locate_config_value(:spot_request_type), } if primary_eni = locate_config_value(:primary_eni) server_def[:network_interfaces] = [ { - :NetworkInterfaceId => primary_eni, - :DeviceIndex => "0" + NetworkInterfaceId: primary_eni, + DeviceIndex: "0", } ] else server_def[:security_group_ids] = locate_config_value(:security_group_ids) server_def[:subnet_id] = locate_config_value(:subnet_id) if vpc_mode? end server_def[:private_ip_address] = locate_config_value(:private_ip_address) if vpc_mode? server_def[:placement_group] = locate_config_value(:placement_group) server_def[:iam_instance_profile_name] = locate_config_value(:iam_instance_profile) - server_def[:tenancy] = "dedicated" if vpc_mode? and locate_config_value(:dedicated_instance) - server_def[:associate_public_ip] = locate_config_value(:associate_public_ip) if vpc_mode? and config[:associate_public_ip] + server_def[:tenancy] = "dedicated" if vpc_mode? && locate_config_value(:dedicated_instance) + server_def[:associate_public_ip] = locate_config_value(:associate_public_ip) if vpc_mode? && config[:associate_public_ip] - if locate_config_value(:winrm_transport) == 'ssl' + if locate_config_value(:winrm_transport) == "ssl" if locate_config_value(:aws_user_data) begin user_data = File.readlines(locate_config_value(:aws_user_data)) if config[:create_ssl_listener] user_data = process_user_data(user_data) end user_data = user_data.join - server_def.merge!(:user_data => user_data) + server_def.merge!(user_data: user_data) rescue ui.warn("Cannot read #{locate_config_value(:aws_user_data)}: #{$!.inspect}. Ignoring option.") end else if config[:create_ssl_listener] - server_def.merge!(:user_data => "<powershell>\n" + ssl_config_user_data + "</powershell>\n") + server_def[:user_data] = "<powershell>\n" + ssl_config_user_data + "</powershell>\n" end end else if locate_config_value(:aws_user_data) begin - server_def.merge!(:user_data => File.read(locate_config_value(:aws_user_data))) + server_def.merge!(user_data: File.read(locate_config_value(:aws_user_data))) rescue ui.warn("Cannot read #{locate_config_value(:aws_user_data)}: #{$!.inspect}. Ignoring option.") end end end @@ -1239,21 +1218,21 @@ exit 1 end server_def[:block_device_mapping] = [{ - 'DeviceName' => ami_map["deviceName"], - 'Ebs.VolumeSize' => ebs_size, - 'Ebs.DeleteOnTermination' => delete_term, - 'Ebs.VolumeType' => config[:ebs_volume_type], + "DeviceName" => ami_map["deviceName"], + "Ebs.VolumeSize" => ebs_size, + "Ebs.DeleteOnTermination" => delete_term, + "Ebs.VolumeType" => config[:ebs_volume_type], }] - server_def[:block_device_mapping].first['Ebs.Iops'] = iops_rate unless iops_rate.empty? - server_def[:block_device_mapping].first['Ebs.Encrypted'] = true if locate_config_value(:ebs_encrypted) + server_def[:block_device_mapping].first["Ebs.Iops"] = iops_rate unless iops_rate.empty? + server_def[:block_device_mapping].first["Ebs.Encrypted"] = true if locate_config_value(:ebs_encrypted) end (config[:ephemeral] || []).each_with_index do |device_name, i| - server_def[:block_device_mapping] = (server_def[:block_device_mapping] || []) << {'VirtualName' => "ephemeral#{i}", 'DeviceName' => device_name} + server_def[:block_device_mapping] = (server_def[:block_device_mapping] || []) << { "VirtualName" => "ephemeral#{i}", "DeviceName" => device_name } end ## cannot pass disable_api_termination option to the API when using spot instances ## server_def[:disable_api_termination] = locate_config_value(:disable_api_termination) if locate_config_value(:spot_price).nil? @@ -1298,39 +1277,39 @@ end end def wait_for_tunnelled_sshd(ssh_gateway, hostname) initial = true - print(".") until tunnel_test_ssh(ssh_gateway, hostname) { + print(".") until tunnel_test_ssh(ssh_gateway, hostname) do if initial initial = false sleep (vpc_mode? ? 40 : 10) else sleep 10 end puts("done") - } + end end def tunnel_test_ssh(ssh_gateway, hostname, &block) status = false gateway = configure_ssh_gateway(ssh_gateway) gateway.open(hostname, config[:ssh_port]) do |local_tunnel_port| - status = tcp_test_ssh('localhost', local_tunnel_port, &block) + status = tcp_test_ssh("localhost", local_tunnel_port, &block) end status rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError sleep 2 false rescue Errno::EPERM, Errno::ETIMEDOUT false end def configure_ssh_gateway(ssh_gateway) - gw_host, gw_user = ssh_gateway.split('@').reverse - gw_host, gw_port = gw_host.split(':') - gateway_options = { :port => gw_port || 22 } + gw_host, gw_user = ssh_gateway.split("@").reverse + gw_host, gw_port = gw_host.split(":") + gateway_options = { port: gw_port || 22 } # Load the SSH config for the SSH gateway host. # Set the gateway user if it was not part of the # SSH gateway string, and use any configured # SSH keys. @@ -1352,19 +1331,19 @@ Net::SSH::Gateway.new(gw_host, gw_user, gateway_options) end def wait_for_direct_sshd(hostname, ssh_port) initial = true - print(".") until tcp_test_ssh(hostname, ssh_port) { + print(".") until tcp_test_ssh(hostname, ssh_port) do if initial initial = false sleep (vpc_mode? ? 40 : 10) else sleep 10 end puts("done") - } + end end def subnet_public_ip_on_launch? connection.subnets.get(server.subnet_id).map_public_ip_on_launch end @@ -1387,28 +1366,28 @@ puts "\nSSH Target Address: #{@ssh_connect_host}(#{connect_attribute})" @ssh_connect_host end def create_tags(hashed_tags) - hashed_tags.each_pair do |key,val| - connection.tags.create :key => key, :value => val, :resource_id => @server.id + hashed_tags.each_pair do |key, val| + connection.tags.create key: key, value: val, resource_id: @server.id end end def associate_eip(elastic_ip) connection.associate_address(server.id, elastic_ip.public_ip, nil, elastic_ip.allocation_id) @server.wait_for(locate_config_value(:aws_connection_timeout)) { public_ip_address == elastic_ip.public_ip } end def validate_nics! valid_nic_ids = connection.network_interfaces.all( - vpc_mode? ? { 'vpc-id' => vpc_id } : {} + vpc_mode? ? { "vpc-id" => vpc_id } : {} ).map(&:network_interface_id) invalid_nic_ids = locate_config_value(:network_interfaces) - valid_nic_ids return true if invalid_nic_ids.empty? - ui.error 'The following network interfaces are invalid: ' \ + ui.error "The following network interfaces are invalid: " \ "#{invalid_nic_ids.join(', ')}" exit 1 end def vpc_id @@ -1418,16 +1397,16 @@ end def wait_for_nic_attachment attached_nics_count = 0 until attached_nics_count == - locate_config_value(:network_interfaces).count + locate_config_value(:network_interfaces).count attachment_nics = locate_config_value(:network_interfaces).map do |nic_id| - connection.network_interfaces.get(nic_id).attachment['status'] + connection.network_interfaces.get(nic_id).attachment["status"] end - attached_nics_count = attachment_nics.grep('attached').count + attached_nics_count = attachment_nics.grep("attached").count end end def attach_nics attachments = [] @@ -1487,20 +1466,20 @@ sleep 2 false rescue Errno::ENETUNREACH sleep 2 false - ensure + ensure tcp_socket && tcp_socket.close end def tcp_test_ssh(hostname, ssh_port) tcp_socket = TCPSocket.new(hostname, ssh_port) readable = IO.select([tcp_socket], nil, nil, 5) if readable ssh_banner = tcp_socket.gets - if ssh_banner.nil? or ssh_banner.empty? + if ssh_banner.nil? || ssh_banner.empty? false else Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{ssh_banner}") yield true @@ -1523,12 +1502,12 @@ ensure tcp_socket && tcp_socket.close end def decrypt_admin_password(encoded_password, key) - require 'base64' - require 'openssl' + require "base64" + require "openssl" private_key = OpenSSL::PKey::RSA.new(key) encrypted_password = Base64.decode64(encoded_password) password = private_key.private_decrypt(encrypted_password) password end @@ -1562,25 +1541,25 @@ locate_config_value(:winrm_password) end end def load_winrm_deps - require 'winrm' - require 'chef/knife/winrm' - require 'chef/knife/bootstrap_windows_winrm' - require 'chef/knife/bootstrap_windows_ssh' - require 'chef/knife/core/windows_bootstrap_context' + require "winrm" + require "chef/knife/winrm" + require "chef/knife/bootstrap_windows_winrm" + require "chef/knife/bootstrap_windows_ssh" + require "chef/knife/core/windows_bootstrap_context" end - #Returns the name of node after evaluation of server id if %s is present. - #Eg: "Test-%s" will return "Test-i-12345" in case the instance id is i-12345 + # Returns the name of node after evaluation of server id if %s is present. + # Eg: "Test-%s" will return "Test-i-12345" in case the instance id is i-12345 def evaluate_node_name(node_name) - return node_name%server.id + node_name % server.id end def create_volume_tags(hashed_volume_tags) - hashed_volume_tags.each_pair do |key,val| - connection.tags.create :key => key, :value => val, :resource_id => @server.block_device_mapping.first['volumeId'] + hashed_volume_tags.each_pair do |key, val| + connection.tags.create key: key, value: val, resource_id: @server.block_device_mapping.first["volumeId"] end end end end