class Chef::Knife::Cloud::OpenstackServerCreate

Public Instance Methods

after_exec_command() click to toggle source

Setup the floating ip after server creation.

Calls superclass method
# File lib/chef/knife/openstack_server_create.rb, line 92
def after_exec_command
  Chef::Log.debug("Addresses #{server.addresses}")
  msg_pair("Public IP Address", primary_public_ip_address(server.addresses)) if primary_public_ip_address(server.addresses)
  msg_pair("Private IP Address", primary_private_ip_address(server.addresses)) if primary_private_ip_address(server.addresses)

  floating_address = config[:openstack_floating_ip]
  bind_ip = primary_network_ip_address(server.addresses, server.addresses.keys[0])
  Chef::Log.debug("Floating IP Address requested #{floating_address}")
  unless floating_address == "-1" # no floating IP requested
    addresses = service.connection.addresses
    # floating requested without value
    if floating_address.nil?
      free_floating = addresses.find_index { |a| a.fixed_ip.nil? }
      begin
        if free_floating.nil? # no free floating IP found
          error_message = "Unable to assign a Floating IP from allocated IPs."
          ui.fatal(error_message)
          raise CloudExceptions::ServerSetupError, error_message
        else
          floating_address = addresses[free_floating].ip
        end
      rescue CloudExceptions::ServerSetupError => e
        cleanup_on_failure
        raise e
      end
    end

    # Pull the port_id for the associate_floating_ip
    port_id = @service.network.list_ports[:body]["ports"].find { |x| x["fixed_ips"][0]["ip_address"] == bind_ip }["id"]
    fixed_ip_address = service.network.list_ports[:body]["ports"].find { |x| x["id"] == port_id }["fixed_ips"][0]["ip_address"]

    floating_ip_id = get_floating_ip_id(floating_address)
    # Associate the floating ip via the neutron/network api
    @service.network.associate_floating_ip(floating_ip_id, port_id, fixed_ip_address: fixed_ip_address)

    # a bit of a hack, but server.reload takes a long time
    (server.addresses["public"] ||= []) << { "version" => 4, "addr" => floating_address }
    msg_pair("Floating IP Address", floating_address)
  end

  Chef::Log.debug("Addresses #{server.addresses}")
  Chef::Log.debug("Public IP Address actual: #{primary_public_ip_address(server.addresses)}") if primary_public_ip_address(server.addresses)

  msg_pair("Private IP Address", primary_private_ip_address(server.addresses)) if primary_private_ip_address(server.addresses)
  super
end
before_bootstrap() click to toggle source
Calls superclass method
# File lib/chef/knife/openstack_server_create.rb, line 139
def before_bootstrap
  super

  # Use SSH password either specified from command line or from openstack server instance
  config[:ssh_password] = config[:ssh_password] || server.password unless config[:openstack_ssh_key_id]

  # The bootstrap network is always initialized to 'public' when a network name isn't specified.  Therefore,
  # only set the bootstrap network to 'private' if still initialized to public and nothing was specified for
  # the private network name.
  config[:bootstrap_network] = "private" if config[:private_network] && config[:bootstrap_network] == "public"

  # Which IP address to bootstrap
  unless config[:network] # --no-network
    bootstrap_ip_address = primary_public_ip_address(server.addresses) ||
      primary_private_ip_address(server.addresses) ||
      server.addresses.first[1][0]["addr"]
    Chef::Log.debug("No Bootstrap Network: #{config[:bootstrap_network]}")
  else
    bootstrap_ip_address = primary_network_ip_address(server.addresses, config[:bootstrap_network])
    Chef::Log.debug("Bootstrap Network: #{config[:bootstrap_network]}")
  end

  Chef::Log.debug("Bootstrap IP Address: #{bootstrap_ip_address}")
  if bootstrap_ip_address.nil?
    error_message = "No IP address available for bootstrapping."
    ui.error(error_message)
    raise CloudExceptions::BootstrapError, error_message
  end
  config[:bootstrap_ip_address] = bootstrap_ip_address

  config[:hints] ||= {}
  config[:hints]["openstack"] ||= {}
end
before_exec_command() click to toggle source
Calls superclass method
# File lib/chef/knife/openstack_server_create.rb, line 39
def before_exec_command
  super
  # setup the create options
  @create_options = {
    server_def: {
      # servers require a name, knife-cloud generates the chef_node_name
      :name => config[:chef_node_name],
      :image_ref => service.get_image(config[:image]).id,
      :flavor_ref => service.get_flavor(config[:flavor]).id,
      :security_groups => config[:openstack_security_groups],
      :availability_zone => config[:availability_zone],
      "os:scheduler_hints" => config[:openstack_scheduler_hints],
      :metadata => config[:metadata],
      :key_name => config[:openstack_ssh_key_id],
    },
    server_create_timeout: config[:server_create_timeout],
  }
  unless config[:openstack_volumes].nil?
    counter = 99
    @create_options[:server_def][:block_device_mapping] = config[:openstack_volumes].map do |vol|
      counter += 1
      {
        volume_id: vol,
        delete_on_termination: false,
        device_name: "/dev/vd" + counter.chr,
        volume_size: nil,
      }
    end
  end

  @create_options[:server_def][:user_data] = config[:user_data] if config[:user_data]
  @create_options[:server_def][:nics] = config[:network_ids].map { |nic| nic_id = { "net_id" => nic } } if config[:network_ids]

  Chef::Log.debug("Create server params - server_def = #{@create_options[:server_def]}")
  # set columns_with_info map
  @columns_with_info = [
    { label: "Instance ID", key: "id" },
    { label: "Name", key: "name" },
    { label: "Public IP", key: "addresses", value_callback: method(:primary_public_ip_address) },
    { label: "Private IP", key: "addresses", value_callback: method(:primary_private_ip_address) },
    { label: "Flavor", key: "flavor", value_callback: method(:get_id) },
    { label: "Image", key: "image", value_callback: method(:get_id) },
    { label: "Keypair", key: "key_name" },
    { label: "State", key: "state" },
    { label: "Availability Zone", key: "availability_zone" },
  ]
end
get_floating_ip_id(floating_address) click to toggle source
# File lib/chef/knife/openstack_server_create.rb, line 234
def get_floating_ip_id(floating_address)
  # required for this method to work
  floating_ip_id = -1
  # Figure out the id for the port that the floating ip you requested
  @service.network.list_floating_ips[:body]["floatingips"].each do |x|
    if x["floating_ip_address"] == floating_address
      floating_ip_id = x["id"]
    end
  end
  floating_ip_id
end
get_id(value) click to toggle source
# File lib/chef/knife/openstack_server_create.rb, line 87
def get_id(value)
  value["id"]
end
is_flavor_valid?() click to toggle source
# File lib/chef/knife/openstack_server_create.rb, line 196
def is_flavor_valid?
  service.get_flavor(config[:flavor]).nil? ? false : true
end
is_floating_ip_valid?() click to toggle source
# File lib/chef/knife/openstack_server_create.rb, line 200
def is_floating_ip_valid?
  address = config[:openstack_floating_ip]

  return true if address == "-1" # no floating IP requested

  addresses = service.connection.addresses
  return false if addresses.empty? # no floating IPs

  # floating requested without value
  if address.nil?
    if addresses.find_index { |a| a.fixed_ip.nil? }
      true
    else
      false # no floating IPs available
    end
  else
    # floating requested with value
    if addresses.find_index { |a| a.ip == address }
      true
    else
      false # requested floating IP does not exist
    end
  end
end
is_image_valid?() click to toggle source
# File lib/chef/knife/openstack_server_create.rb, line 192
def is_image_valid?
  service.get_image(config[:image]).nil? ? false : true
end
post_connection_validations() click to toggle source
# File lib/chef/knife/openstack_server_create.rb, line 225
def post_connection_validations
  errors = []
  errors << "You have not provided a valid image ID. Please note the options for this value are -I or --image." unless is_image_valid?
  errors << "You have not provided a valid flavor ID. Please note the options for this value are -f or --flavor." unless is_flavor_valid?
  errors << "You have either requested an invalid floating IP address or none are available." unless is_floating_ip_valid?
  error_message = ""
  raise CloudExceptions::ValidationError, error_message if errors.each { |e| ui.error(e); error_message = "#{error_message} #{e}." }.any?
end
validate_params!() click to toggle source
# File lib/chef/knife/openstack_server_create.rb, line 173
def validate_params!
  # set param vm_name to a random value if the name is not set by the user (plugin)
  config[:chef_node_name] = get_node_name(config[:chef_node_name], config[:chef_node_name_prefix])

  errors = []

  if config[:connection_protocol] == "winrm"
    if config[:connection_password].nil?
      errors << "You must provide Connection Password."
    end
  elsif config[:connection_protocol] != "ssh"
    errors << "You must provide a valid bootstrap protocol. options [ssh/winrm]. For linux type images, options [ssh]"
  end

  errors << "You must provide --image-os-type option [windows/linux]" unless %w{windows linux}.include?(config[:image_os_type])
  error_message = ""
  raise CloudExceptions::ValidationError, error_message if errors.each { |e| ui.error(e); error_message = "#{error_message} #{e}." }.any?
end