Skip to content
This repository has been archived by the owner on Jul 24, 2020. It is now read-only.

Commit

Permalink
merge KNIFE_RACKSPACE-39, v0.6.0
Browse files Browse the repository at this point in the history
  • Loading branch information
mattray committed Oct 10, 2012
1 parent 1caf1be commit 606a43b
Show file tree
Hide file tree
Showing 9 changed files with 193 additions and 52 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## v0.6.0
* KNIFE_RACKSPACE-39 support for Rackspace Open Cloud (v2)
* server list puts the name in second column
* flavor list supports VCPUs for v2
* server delete for v2 will attempt the name when purging since we set the name
* docs updated to reflect all of the regions and APIs supported

## v0.5.16
* KNIFE_RACKSPACE-36 Changed to code to use IP address for bootstrapping
* KNIFE_RACKSPACE-38 Support the -P --purge option
Expand Down
29 changes: 22 additions & 7 deletions README.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

= DESCRIPTION:

This is the official Opscode Knife plugin for Rackspace. This plugin gives knife the ability to create, bootstrap, and manage servers on the Rackspace Cloud.
This is the official Opscode Knife plugin for Rackspace Cloud Servers. This plugin gives knife the ability to create, bootstrap, and manage servers on all the regions for Rackspace Cloud Servers.

= INSTALLATION:

Expand Down Expand Up @@ -33,10 +33,23 @@ You also have the option of passing your Rackspace API Username/Key into the ind
# provision a new 1GB Ubuntu 10.04 webserver
knife rackspace server create -I 112 -f 3 -A 'Your Rackspace API username' -K "Your Rackspace API Key" -r 'role[webserver]'

This plugin also has support for authenticating against an alternate API Auth URL. This is useful if you are a Rackspace Cloud UK user or OpenStack early adopter. Here is an example of configuring knife for Rackspace Cloud UK:
To select for the new OpenStack-based "Rackspace Open Cloud" API (aka 'v2'), you can use the <tt>--rackspace-version v2</tt> command option. 'v1' is still the default, so if you're using exclusively 'v2' you will probably want to add the following to your <tt>knife.rb</tt>:

knife[:rackspace_version] = 'v2'

This plugin also has support for authenticating against an alternate API Auth URL. This is useful if you are a Rackspace Cloud UK user, here is an example of configuring your <tt>knife.rb</tt>:

knife[:rackspace_api_auth_url] = "lon.auth.api.rackspacecloud.com"

This plugin also has support for specifying which region to create servers into:

knife[:rackspace_endpoint] = "https://dfw.servers.api.rackspacecloud.com/v2"

valid options include:
DFW_ENDPOINT = 'https://dfw.servers.api.rackspacecloud.com/v2'
ORD_ENDPOINT = 'https://ord.servers.api.rackspacecloud.com/v2'
LON_ENDPOINT = 'https://lon.servers.api.rackspacecloud.com/v2'

Additionally the following options may be set in your `knife.rb`:

* flavor
Expand All @@ -50,23 +63,25 @@ This plugin provides the following Knife subcommands. Specific command options c

== knife rackspace server create

Provisions a new server in the Rackspace Cloud and then perform a Chef bootstrap (using the SSH protocol). The goal of the bootstrap is to get Chef installed on the target system so it can run Chef Client with a Chef Server. The main assumption is a baseline OS installation exists (provided by the provisioning). It is primarily intended for Chef Client systems that talk to a Chef server. By default the server is bootstrapped using the {ubuntu10.04-gems}[https://github.com/opscode/chef/blob/master/chef/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb] template. This can be overridden using the <tt>-d</tt> or <tt>--template-file</tt> command options.
Provisions a new server in the Rackspace Cloud and then perform a Chef bootstrap (using the SSH protocol). The goal of the bootstrap is to get Chef installed on the target system so it can run Chef Client with a Chef Server. The main assumption is a baseline OS installation exists (provided by the provisioning). It is primarily intended for Chef Client systems that talk to a Chef server. By default the server is bootstrapped using the {chef-full}[https://github.com/opscode/chef/blob/master/chef/lib/chef/knife/bootstrap/chef-full.erb] template. This can be overridden using the <tt>-d</tt> or <tt>--template-file</tt> command options.

If no name is provided, nodes created with the v1 API are named after their instance ID, with the v2 API they are given a random 'rs-XXXXXXXXX' name.

== knife rackspace server delete

Deletes an existing server in the currently configured Rackspace Cloud account by the server/instance id. You can find the instance id by entering 'knife rackspace server list'. Please note - this does not delete the associated node and client objects from the Chef server unless you pass the <tt>-P</tt> or <tt>--purge</tt> command option.
Deletes an existing server in the currently configured Rackspace Cloud account by the server/instance id. You can find the instance id by entering 'knife rackspace server list'. Please note - this does not delete the associated node and client objects from the Chef server unless you pass the <tt>-P</tt> or <tt>--purge</tt> command option. Using the <tt>--purge</tt> option with v2 nodes will attempt to delete the node and client by the name of the node.

== knife rackspace server list

Outputs a list of all servers in the currently configured Rackspace Cloud account. Please note - this shows all instances associated with the account, some of which may not be currently managed by the Chef server.
Outputs a list of all servers in the currently configured Rackspace Cloud account. Please note - this shows all instances associated with the account, some of which may not be currently managed by the Chef server. You may need to use the <tt>--rackspace-version</tt> and possibly a <tt>--rackspace-endpoint</tt> options to see nodes in different Rackspace regions.

== knife rackspace flavor list

Outputs a list of all available flavors (available hardware configuration for a server) available to the currently configured Rackspace Cloud account. Each flavor has a unique combination of disk space, memory capacity and priority for CPU time. This data can be useful when choosing a flavor id to pass to the <tt>knife rackspace server create</tt> subcommand.
Outputs a list of all available flavors (available hardware configuration for a server) available to the currently configured Rackspace Cloud account. Each flavor has a unique combination of disk space, memory capacity and priority for CPU time. This data can be useful when choosing a flavor id to pass to the <tt>knife rackspace server create</tt> subcommand. You may need to use the <tt>--rackspace-version</tt> and possibly a <tt>--rackspace-endpoint</tt> options to see nodes in different Rackspace regions.

== knife rackspace image list

Outputs a list of all available images available to the currently configured Rackspace Cloud account. An image is a collection of files used to create or rebuild a server. Rackspace provides a number of pre-built OS images by default. This data can be useful when choosing an image id to pass to the <tt>knife rackspace server create</tt> subcommand.
Outputs a list of all available images available to the currently configured Rackspace Cloud account. An image is a collection of files used to create or rebuild a server. Rackspace provides a number of pre-built OS images by default. This data can be useful when choosing an image id to pass to the <tt>knife rackspace server create</tt> subcommand. You may need to use the <tt>--rackspace-version</tt> and possibly a <tt>--rackspace-endpoint</tt> options to see nodes in different Rackspace regions.


= LICENSE:
Expand Down
2 changes: 1 addition & 1 deletion knife-rackspace.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Gem::Specification.new do |s|
s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.add_dependency "fog", "~> 1.3"
s.add_dependency "fog", "~> 1.6"
s.add_dependency "chef", ">= 0.10.10"
s.require_paths = ["lib"]

Expand Down
107 changes: 96 additions & 11 deletions lib/chef/knife/rackspace_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,22 +47,57 @@ def self.included(includer)
:description => "Your rackspace API username",
:proc => Proc.new { |username| Chef::Config[:knife][:rackspace_username] = username }

option :rackspace_version,
:long => '--rackspace-version VERSION',
:description => 'Rackspace Cloud Servers API version',
:default => "v1",
:proc => Proc.new { |version| Chef::Config[:knife][:rackspace_version] = version }

option :rackspace_api_auth_url,
:long => "--rackspace-api-auth-url URL",
:description => "Your rackspace API auth url",
:default => "auth.api.rackspacecloud.com",
:proc => Proc.new { |url| Chef::Config[:knife][:rackspace_api_auth_url] = url }

option :rackspace_endpoint,
:long => "--rackspace-endpoint URL",
:description => "Your rackspace API endpoint",
:default => "https://dfw.servers.api.rackspacecloud.com/v2",
:proc => Proc.new { |url| Chef::Config[:knife][:rackspace_endpoint] = url }
end
end

def connection
@connection ||= begin
connection = Fog::Compute.new(
:provider => 'Rackspace',
:rackspace_api_key => Chef::Config[:knife][:rackspace_api_key],
:rackspace_username => (Chef::Config[:knife][:rackspace_username] || Chef::Config[:knife][:rackspace_api_username]),
:rackspace_auth_url => Chef::Config[:knife][:rackspace_api_auth_url] || config[:rackspace_api_auth_url]
)
Chef::Log.debug("version #{Chef::Config[:knife][:rackspace_version]}") #config file
Chef::Log.debug("version #{config[:rackspace_version]}") #cli
Chef::Log.debug("rackspace_api_key #{Chef::Config[:knife][:rackspace_api_key]}")
Chef::Log.debug("rackspace_username #{Chef::Config[:knife][:rackspace_username]}")
Chef::Log.debug("rackspace_api_username #{Chef::Config[:knife][:rackspace_api_username]}")
Chef::Log.debug("rackspace_auth_url #{Chef::Config[:knife][:rackspace_auth_url]}")
Chef::Log.debug("rackspace_auth_url #{config[:rackspace_api_auth_url]}")
Chef::Log.debug("rackspace_endpoint #{Chef::Config[:knife][:rackspace_endpoint]}")
Chef::Log.debug("rackspace_endpoint #{config[:rackspace_endpoint]}")
if (Chef::Config[:knife][:rackspace_version] == 'v2') || (config[:rackspace_version] == 'v2')
@connection ||= begin
connection = Fog::Compute.new(
:provider => 'Rackspace',
:version => 'v2',
:rackspace_api_key => Chef::Config[:knife][:rackspace_api_key],
:rackspace_username => (Chef::Config[:knife][:rackspace_username] || Chef::Config[:knife][:rackspace_api_username]),
:rackspace_auth_url => Chef::Config[:knife][:rackspace_api_auth_url] || config[:rackspace_api_auth_url],
:rackspace_endpoint => Chef::Config[:knife][:rackspace_endpoint] || config[:rackspace_endpoint]
)
end
else
@connection ||= begin
connection = Fog::Compute.new(
:provider => 'Rackspace',
:version => 'v1',
:rackspace_api_key => Chef::Config[:knife][:rackspace_api_key],
:rackspace_username => (Chef::Config[:knife][:rackspace_username] || Chef::Config[:knife][:rackspace_api_username]),
:rackspace_auth_url => Chef::Config[:knife][:rackspace_api_auth_url] || config[:rackspace_api_auth_url]
)
end
end
end

Expand All @@ -77,15 +112,65 @@ def msg_pair(label, value, color=:cyan)
end
end

def public_ip(server)
if version_one?
v1_public_ip(server)
else
v2_public_ip(server)
end
end

def private_ip(server)
if version_one?
v1_private_ip(server)
else
v2_private_ip(server)
end
end

def public_dns_name(server)
ip_address = public_ip(server)

@public_dns_name ||= begin
Resolv.getname(server.addresses["public"][0])
Resolv.getname(ip_address)
rescue
"#{server.addresses["public"][0].gsub('.','-')}.static.cloud-ips.com"
"#{ip_address.gsub('.','-')}.static.cloud-ips.com"
end
end

private

def version_one?
rackspace_api_version == 'v1'
end

def rackspace_api_version
version = Chef::Config[:knife][:rackspace_version] || 'v1'
version.downcase
end

def v1_public_ip(server)
server.public_ip_address == nil ? "" : server.public_ip_address
end

def v1_private_ip(server)
server.addresses["private"].first == nil ? "" : server.addresses["private"].first
end

def v2_public_ip(server)
public_ips = server.addresses["public"]
extract_ipv4_address(public_ips) if public_ips
end

def v2_private_ip(server)
private_ips = server.addresses["private"]
extract_ipv4_address(private_ips) if private_ips
end

def extract_ipv4_address(ip_addresses)
address = ip_addresses.select { |ip| ip["version"] == 4 }.first
address ? address["addr"] : ""
end
end
end
end


33 changes: 24 additions & 9 deletions lib/chef/knife/rackspace_flavor_list.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,36 @@ class RackspaceFlavorList < Knife
banner "knife rackspace flavor list (options)"

def run
flavor_list = [
ui.color('ID', :bold),
ui.color('Name', :bold),
ui.color('Architecture', :bold),
ui.color('RAM', :bold),
ui.color('Disk', :bold)
]
if version_one?
flavor_list = [
ui.color('ID', :bold),
ui.color('Name', :bold),
ui.color('Architecture', :bold),
ui.color('RAM', :bold),
ui.color('Disk', :bold)
]
else
flavor_list = [
ui.color('ID', :bold),
ui.color('Name', :bold),
ui.color('VCPUs', :bold),
ui.color('RAM', :bold),
ui.color('Disk', :bold)
]
end
connection.flavors.sort_by(&:id).each do |flavor|

flavor = connection.flavors.get(flavor.id)
bits = flavor.respond_to?(:bits) ? "#{flavor.bits.to_s}-bit" : ""

flavor_list << flavor.id.to_s
flavor_list << flavor.name
flavor_list << "#{flavor.bits.to_s}-bit"
flavor_list << bits if version_one?
flavor_list << flavor.vcpus.to_s unless version_one?
flavor_list << "#{flavor.ram.to_s}"
flavor_list << "#{flavor.disk.to_s} GB"
end
puts ui.list(flavor_list, :uneven_columns_across, 5)
puts ui.list(flavor_list, :uneven_columns_across, 5)
end
end
end
Expand Down
36 changes: 24 additions & 12 deletions lib/chef/knife/rackspace_server_create.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#
# Author:: Adam Jacob (<[email protected]>)
# Copyright:: Copyright (c) 2009 Opscode, Inc.
# Author:: Matt Ray (<[email protected]>)
# Copyright:: Copyright (c) 2009-2012 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -45,7 +46,7 @@ class RackspaceServerCreate < Knife
:short => "-I IMAGE",
:long => "--image IMAGE",
:description => "The image of the server",
:proc => Proc.new { |i| Chef::Config[:knife][:image] = i.to_i }
:proc => Proc.new { |i| Chef::Config[:knife][:image] = i.to_s }

option :server_name,
:short => "-S NAME",
Expand Down Expand Up @@ -160,12 +161,14 @@ def run
exit 1
end

node_name = get_node_name(config[:chef_node_name] || config[:server_name])

server = connection.servers.create(
:name => config[:server_name],
:name => node_name,
:image_id => Chef::Config[:knife][:image],
:flavor_id => locate_config_value(:flavor),
:metadata => Chef::Config[:knife][:rackspace_metadata]
)
)

msg_pair("Instance ID", server.id)
msg_pair("Host ID", server.host_id)
Expand All @@ -182,16 +185,16 @@ def run
puts("\n")

msg_pair("Public DNS Name", public_dns_name(server))
msg_pair("Public IP Address", server.addresses['public'][0])
msg_pair("Private IP Address", server.addresses['private'][0])
msg_pair("Public IP Address", public_ip(server))
msg_pair("Private IP Address", private_ip(server))
msg_pair("Password", server.password)

print "\n#{ui.color("Waiting for sshd", :magenta)}"

#which IP address to bootstrap
bootstrap_ip_address = server.addresses['public'][0] if server.public_ip_address
bootstrap_ip_address = public_ip(server)
if config[:private_network]
bootstrap_ip_address = server.addresses['private'][0]
bootstrap_ip_address = private_ip(server)
end
Chef::Log.debug("Bootstrap IP Address #{bootstrap_ip_address}")
if bootstrap_ip_address.nil?
Expand All @@ -203,7 +206,6 @@ def run
sleep @initial_sleep_delay ||= 10
puts("done")
}

bootstrap_for_node(server, bootstrap_ip_address).run

puts "\n"
Expand All @@ -214,8 +216,8 @@ def run
msg_pair("Image", server.image.name)
msg_pair("Metadata", server.metadata)
msg_pair("Public DNS Name", public_dns_name(server))
msg_pair("Public IP Address", server.addresses["public"][0])
msg_pair("Private IP Address", server.addresses["private"][0])
msg_pair("Public IP Address", public_ip(server))
msg_pair("Private IP Address", private_ip(server))
msg_pair("Password", server.password)
msg_pair("Environment", config[:environment] || '_default')
msg_pair("Run List", config[:run_list].join(', '))
Expand All @@ -230,7 +232,11 @@ def bootstrap_for_node(server, bootstrap_ip_address)
bootstrap.config[:ssh_password] = server.password
bootstrap.config[:identity_file] = config[:identity_file]
bootstrap.config[:host_key_verify] = config[:host_key_verify]
bootstrap.config[:chef_node_name] = config[:chef_node_name] || server.id
if version_one?
bootstrap.config[:chef_node_name] = config[:chef_node_name] || server.id
else
bootstrap.config[:chef_node_name] = server.name
end
bootstrap.config[:prerelease] = config[:prerelease]
bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
bootstrap.config[:distro] = locate_config_value(:distro)
Expand All @@ -242,5 +248,11 @@ def bootstrap_for_node(server, bootstrap_ip_address)
end

end
#v2 servers require a name, random if chef_node_name is empty, empty if v1
def get_node_name(chef_node_name)
return chef_node_name unless chef_node_name.nil?
#lazy uuids
chef_node_name = "rs-"+rand.to_s.split('.')[1] unless version_one?
end
end
end
Loading

0 comments on commit 606a43b

Please sign in to comment.