knife-ninefold 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +38 -0
- data/lib/chef/knife/ninefold_base.rb +59 -0
- data/lib/chef/knife/ninefold_flavor_list.rb +29 -0
- data/lib/chef/knife/ninefold_image_list.rb +32 -0
- data/lib/chef/knife/ninefold_server_create.rb +153 -0
- data/lib/chef/knife/ninefold_server_delete.rb +55 -0
- data/lib/chef/knife/ninefold_server_list.rb +42 -0
- data/lib/knife-ninefold/version.rb +3 -0
- metadata +75 -0
data/README.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# Knife Ninefold
|
2
|
+
|
3
|
+
## Description
|
4
|
+
|
5
|
+
Knife plugin for ninefold
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
This plugin is distributed as a Ruby Gem. To install:
|
10
|
+
|
11
|
+
gem install knife-ninefold
|
12
|
+
|
13
|
+
## Configuration
|
14
|
+
|
15
|
+
The following parameters need to be set in your knife.rb:
|
16
|
+
|
17
|
+
knife[:ninefold_compute_key] = "Your Ninefold compute API key"
|
18
|
+
knife[:ninefold_compute_secret] = "Your Ninefold compute API secret"
|
19
|
+
|
20
|
+
or added to the command line in the -K and -S parameters
|
21
|
+
|
22
|
+
## Subcommands
|
23
|
+
|
24
|
+
### knife ninefold flavor list
|
25
|
+
|
26
|
+
### knife ninefold image list
|
27
|
+
|
28
|
+
### knife ninefold server create
|
29
|
+
|
30
|
+
Creates a server. By default, a 1.7gb running Ubuntu
|
31
|
+
|
32
|
+
### knife ninefold server list
|
33
|
+
|
34
|
+
### knife ninefold server delete
|
35
|
+
|
36
|
+
## Development
|
37
|
+
|
38
|
+
Run knife through bundler - this will load the in development gem
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'chef/knife'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
module NinefoldBase
|
6
|
+
|
7
|
+
# :nodoc:
|
8
|
+
# Would prefer to do this in a rational way, but can't be done b/c of
|
9
|
+
# Mixlib::CLI's design :(
|
10
|
+
def self.included(includer)
|
11
|
+
includer.class_eval do
|
12
|
+
|
13
|
+
deps do
|
14
|
+
require 'fog'
|
15
|
+
require 'net/ssh/multi'
|
16
|
+
require 'readline'
|
17
|
+
require 'chef/json_compat'
|
18
|
+
|
19
|
+
Chef::Knife::Bootstrap.load_deps
|
20
|
+
end
|
21
|
+
|
22
|
+
option(:ninefold_compute_key,
|
23
|
+
:short => "-K KEY",
|
24
|
+
:long => "--ninefold_compute_key KEY",
|
25
|
+
:description => "Your Ninefold API Key",
|
26
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:ninefold_compute_key] = key })
|
27
|
+
|
28
|
+
option(:ninefold_compute_secret,
|
29
|
+
:short => "-S SECRET",
|
30
|
+
:long => "--ninefold_compute_secret SECRET",
|
31
|
+
:description => "Your Ninefold API Secret Secret",
|
32
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:ninefold_compute_secret] = key })
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def connection
|
38
|
+
unless Chef::Config[:knife][:ninefold_compute_key] && Chef::Config[:knife][:ninefold_compute_secret]
|
39
|
+
ui.error "Ninefold compute key and/or secret not specified with -K and -S parameters,"
|
40
|
+
ui.error "or set in knife.rb with:"
|
41
|
+
ui.error 'knife[:ninefold_compute_key] = "API key"'
|
42
|
+
ui.error 'knife[:ninefold_compute_secret] = "Secret key"'
|
43
|
+
exit 1
|
44
|
+
end
|
45
|
+
@connection ||= Fog::Compute.new(
|
46
|
+
:provider => 'Ninefold',
|
47
|
+
:ninefold_compute_key => Chef::Config[:knife][:ninefold_compute_key],
|
48
|
+
:ninefold_compute_secret => Chef::Config[:knife][:ninefold_compute_secret]
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def locate_config_value(key)
|
53
|
+
key = key.to_sym
|
54
|
+
Chef::Config[:knife][key] || config[key]
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'chef/knife/ninefold_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class NinefoldFlavorList < Knife
|
6
|
+
|
7
|
+
include Knife::NinefoldBase
|
8
|
+
|
9
|
+
banner "knife ninefold flavor list"
|
10
|
+
|
11
|
+
def run
|
12
|
+
$stdout.sync = true
|
13
|
+
|
14
|
+
flavor_list = [
|
15
|
+
ui.color('ID', :bold),
|
16
|
+
ui.color('Name', :bold),
|
17
|
+
ui.color('Description', :bold)
|
18
|
+
]
|
19
|
+
connection.flavors.all.each do |flavor|
|
20
|
+
flavor_list << flavor.identity.to_s
|
21
|
+
flavor_list << flavor.name
|
22
|
+
flavor_list << flavor.displaytext
|
23
|
+
end
|
24
|
+
puts ui.list(flavor_list, :columns_across, 3)
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'chef/knife/ninefold_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class NinefoldImageList < Knife
|
6
|
+
|
7
|
+
include Knife::NinefoldBase
|
8
|
+
|
9
|
+
banner "knife ninefold image list"
|
10
|
+
|
11
|
+
def run
|
12
|
+
$stdout.sync = true
|
13
|
+
|
14
|
+
image_list = [
|
15
|
+
ui.color('ID', :bold),
|
16
|
+
ui.color('Name', :bold),
|
17
|
+
ui.color('Hypervisor', :bold),
|
18
|
+
ui.color('Zone', :bold)
|
19
|
+
]
|
20
|
+
connection.images.all.each do |image|
|
21
|
+
image_list << image.identity.to_s
|
22
|
+
image_list << image.name
|
23
|
+
image_list << image.hypervisor
|
24
|
+
image_list << image.zonename
|
25
|
+
end
|
26
|
+
puts ui.list(image_list, :columns_across, 4)
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'chef/knife/ninefold_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class NinefoldServerCreate < Knife
|
6
|
+
|
7
|
+
include Knife::NinefoldBase
|
8
|
+
|
9
|
+
banner "knife ninefold server create (options)"
|
10
|
+
|
11
|
+
option :flavor,
|
12
|
+
:short => "-f FLAVOR",
|
13
|
+
:long => "--flavor FLAVOR",
|
14
|
+
:description => "The flavor of server; default is 67 - Compute Small PRD (1.7 GB)",
|
15
|
+
:proc => Proc.new { |f| Chef::Config[:knife][:flavor] = f.to_i },
|
16
|
+
:default => 67
|
17
|
+
|
18
|
+
option :image,
|
19
|
+
:short => "-I IMAGE",
|
20
|
+
:long => "--image IMAGE",
|
21
|
+
:description => "The image of the server; Default is 421 - XEN Ubuntu 10.04 LTS 64bit",
|
22
|
+
:proc => Proc.new { |i| Chef::Config[:knife][:image] = i.to_i },
|
23
|
+
:default => 421
|
24
|
+
|
25
|
+
option :server_name,
|
26
|
+
:short => "-S NAME",
|
27
|
+
:long => "--server-name NAME",
|
28
|
+
:description => "The server name"
|
29
|
+
|
30
|
+
option :bootstrap,
|
31
|
+
:short => "-b",
|
32
|
+
:long => "--bootstrap",
|
33
|
+
:description => "If we should chef bootstrap this node; default is to not bootstrap",
|
34
|
+
:boolean => true,
|
35
|
+
:default => false
|
36
|
+
|
37
|
+
option :chef_node_name,
|
38
|
+
:short => "-N NAME",
|
39
|
+
:long => "--node-name NAME",
|
40
|
+
:description => "The Chef node name for your new node"
|
41
|
+
|
42
|
+
option :ssh_user,
|
43
|
+
:short => "-x USERNAME",
|
44
|
+
:long => "--ssh-user USERNAME",
|
45
|
+
:description => "The ssh username; default is 'ubuntu'",
|
46
|
+
:default => "ubuntu"
|
47
|
+
|
48
|
+
option :ssh_password,
|
49
|
+
:short => "-P PASSWORD",
|
50
|
+
:long => "--ssh-password PASSWORD",
|
51
|
+
:description => "The ssh password; default is 'Password01'",
|
52
|
+
:default => "Password01"
|
53
|
+
|
54
|
+
option :identity_file,
|
55
|
+
:short => "-i IDENTITY_FILE",
|
56
|
+
:long => "--identity-file IDENTITY_FILE",
|
57
|
+
:description => "The SSH identity file used for authentication"
|
58
|
+
|
59
|
+
option :prerelease,
|
60
|
+
:long => "--prerelease",
|
61
|
+
:description => "Install the pre-release chef gems"
|
62
|
+
|
63
|
+
option :bootstrap_version,
|
64
|
+
:long => "--bootstrap-version VERSION",
|
65
|
+
:description => "The version of Chef to install",
|
66
|
+
:proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_version] = v }
|
67
|
+
|
68
|
+
option :distro,
|
69
|
+
:short => "-d DISTRO",
|
70
|
+
:long => "--distro DISTRO",
|
71
|
+
:description => "Bootstrap a distro using a template; default is 'ubuntu10.04-gems'",
|
72
|
+
:proc => Proc.new { |d| Chef::Config[:knife][:distro] = d },
|
73
|
+
:default => "ubuntu10.04-gems"
|
74
|
+
|
75
|
+
option :template_file,
|
76
|
+
:long => "--template-file TEMPLATE",
|
77
|
+
:description => "Full path to location of template to use",
|
78
|
+
:proc => Proc.new { |t| Chef::Config[:knife][:template_file] = t },
|
79
|
+
:default => false
|
80
|
+
|
81
|
+
option :run_list,
|
82
|
+
:short => "-r RUN_LIST",
|
83
|
+
:long => "--run-list RUN_LIST",
|
84
|
+
:description => "Comma separated list of roles/recipes to apply",
|
85
|
+
:proc => lambda { |o| o.split(/[\s,]+/) },
|
86
|
+
:default => []
|
87
|
+
|
88
|
+
def run
|
89
|
+
$stdout.sync = true
|
90
|
+
|
91
|
+
server = connection.servers.create(:templateid => locate_config_value(:image),
|
92
|
+
:serviceofferingid => locate_config_value(:flavor),
|
93
|
+
:zoneid => 1,
|
94
|
+
:name => config[:server_name])
|
95
|
+
|
96
|
+
server.reload # fetch generated name etc.
|
97
|
+
|
98
|
+
puts "#{ui.color("Instance ID", :cyan)}: #{server.id}"
|
99
|
+
puts "#{ui.color("Name", :cyan)}: #{server.name}"
|
100
|
+
puts "#{ui.color("Flavor", :cyan)}: #{server.serviceofferingname}"
|
101
|
+
puts "#{ui.color("Image", :cyan)}: #{server.templatename}"
|
102
|
+
|
103
|
+
print "\n#{ui.color("Waiting on server", :magenta)}"
|
104
|
+
# wait for it to be ready to do stuff
|
105
|
+
server.wait_for { print "."; ready? }
|
106
|
+
puts
|
107
|
+
|
108
|
+
@ip = connection.addresses.new(:zoneid => 1)
|
109
|
+
@ip.save
|
110
|
+
@ip.reload
|
111
|
+
print "\n#{ui.color("Waiting on IP address allocation", :magenta)}"
|
112
|
+
@ip.wait_for { print '.' ; ready? }
|
113
|
+
puts "\n"
|
114
|
+
# Enable static NAT to this server
|
115
|
+
@ip.enable_static_nat(server)
|
116
|
+
# Map inbound connections
|
117
|
+
ipfw_tcp = connection.ip_forwarding_rules.new(:address => @ip, :protocol => 'TCP', :startport => 1, :endport => 65535)
|
118
|
+
ipfw_tcp.save
|
119
|
+
ipfw_udp = connection.ip_forwarding_rules.new(:address => @ip, :protocol => 'UDP', :startport => 1, :endport => 65535)
|
120
|
+
ipfw_udp.save
|
121
|
+
print "\n#{ui.color("Waiting on Inbound TCP&UDP connection mapping", :magenta)}"
|
122
|
+
ipfw_tcp.wait_for {print '.' ; ready?}
|
123
|
+
ipfw_udp.wait_for {print '.' ; ready?}
|
124
|
+
puts
|
125
|
+
puts "#{ui.color("Public IP Address", :cyan)}: #{@ip.ipaddress}"
|
126
|
+
|
127
|
+
|
128
|
+
if config[:bootstrap]
|
129
|
+
bootstrap_for_node(server).run
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def bootstrap_for_node(server)
|
134
|
+
bootstrap = Chef::Knife::Bootstrap.new
|
135
|
+
bootstrap.name_args = [@ip.ipaddress]
|
136
|
+
bootstrap.config[:run_list] = config[:run_list]
|
137
|
+
bootstrap.config[:ssh_user] = config[:ssh_user] || "root"
|
138
|
+
bootstrap.config[:ssh_password] = config[:ssh_password]
|
139
|
+
bootstrap.config[:identity_file] = config[:identity_file]
|
140
|
+
bootstrap.config[:chef_node_name] = config[:chef_node_name] || server.name
|
141
|
+
bootstrap.config[:prerelease] = config[:prerelease]
|
142
|
+
bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
|
143
|
+
bootstrap.config[:distro] = locate_config_value(:distro)
|
144
|
+
# bootstrap will run as root...sudo (by default) also messes up Ohai on CentOS boxes
|
145
|
+
bootstrap.config[:use_sudo] = true unless config[:ssh_user] == 'root'
|
146
|
+
bootstrap.config[:template_file] = locate_config_value(:template_file)
|
147
|
+
bootstrap.config[:environment] = config[:environment]
|
148
|
+
bootstrap
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'chef/knife/ninefold_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class NinefoldServerDelete < Knife
|
6
|
+
|
7
|
+
include Knife::NinefoldBase
|
8
|
+
|
9
|
+
banner "knife ninefold server delete SERVER_ID [SERVER_ID..]"
|
10
|
+
|
11
|
+
def run
|
12
|
+
$stdout.sync = true
|
13
|
+
|
14
|
+
@name_args.each do |instance_id|
|
15
|
+
|
16
|
+
server = connection.servers.get(instance_id)
|
17
|
+
|
18
|
+
addrs = connection.addresses.all.select {|a| a.isstaticnat.to_s == "true" && a.virtualmachineid == server.id}
|
19
|
+
|
20
|
+
msg("Instance ID", server.id.to_s)
|
21
|
+
msg("Name", server.name)
|
22
|
+
msg("Flavor", server.serviceofferingname)
|
23
|
+
msg("Image", server.templatename)
|
24
|
+
msg("Public IP", addrs[0].ipaddress) if addrs[0]
|
25
|
+
|
26
|
+
puts "\n"
|
27
|
+
confirm("Do you really want to delete this server")
|
28
|
+
|
29
|
+
server.destroy
|
30
|
+
ui.warn("Deleted server #{server.id} named #{server.name}")
|
31
|
+
if addrs[0]
|
32
|
+
# addrs[0].disable_static_nat
|
33
|
+
# print "\n#{ui.color("Waiting on static nat disabling", :magenta)}"
|
34
|
+
# addrs[0].wait_for { print '.' ; ready? }
|
35
|
+
# puts
|
36
|
+
addrs[0].destroy
|
37
|
+
# print "\n#{ui.color("Waiting on ip address release", :magenta)}"
|
38
|
+
# addrs[0].wait_for { print '.' ; ready? }
|
39
|
+
# puts
|
40
|
+
ui.warn("Removed public IP allocation: #{addrs[0].ipaddress}")
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def msg(label, value)
|
47
|
+
if value && !value.empty?
|
48
|
+
puts "#{ui.color(label, :cyan)}: #{value}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'chef/knife/ninefold_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class NinefoldServerList < Knife
|
6
|
+
|
7
|
+
include Knife::NinefoldBase
|
8
|
+
|
9
|
+
banner "knife ninefold server list"
|
10
|
+
|
11
|
+
def run
|
12
|
+
$stdout.sync = true
|
13
|
+
|
14
|
+
server_list = [
|
15
|
+
ui.color('Instance ID', :bold),
|
16
|
+
ui.color('Name', :bold),
|
17
|
+
ui.color('Public IP', :bold),
|
18
|
+
ui.color('Private IP', :bold),
|
19
|
+
ui.color('Flavor', :bold),
|
20
|
+
ui.color('Image', :bold),
|
21
|
+
ui.color('Zone', :bold)
|
22
|
+
]
|
23
|
+
connection.servers.all.each do |server|
|
24
|
+
# Get public IP:
|
25
|
+
addrs = connection.addresses.all.select {|a| a.isstaticnat.to_s == "true" && a.virtualmachineid == server.id}
|
26
|
+
public_ip = addrs[0] ? addrs[0].ipaddress : 'No public IP'
|
27
|
+
|
28
|
+
server_list << server.identity.to_s
|
29
|
+
server_list << server.name
|
30
|
+
server_list << public_ip
|
31
|
+
server_list << server.ipaddress
|
32
|
+
server_list << server.serviceofferingname
|
33
|
+
server_list << server.templatename
|
34
|
+
server_list << server.zonename
|
35
|
+
end
|
36
|
+
puts ui.list(server_list, :columns_across, 7)
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: knife-ninefold
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Lincoln Stoll
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-12-01 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: chef
|
16
|
+
requirement: &70296831106840 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70296831106840
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: fog
|
27
|
+
requirement: &70296831106420 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70296831106420
|
36
|
+
description: Ninefold Support for Chef's Knife Command
|
37
|
+
email: lstoll@lstoll.net
|
38
|
+
executables: []
|
39
|
+
extensions: []
|
40
|
+
extra_rdoc_files:
|
41
|
+
- README.md
|
42
|
+
files:
|
43
|
+
- README.md
|
44
|
+
- lib/chef/knife/ninefold_base.rb
|
45
|
+
- lib/chef/knife/ninefold_flavor_list.rb
|
46
|
+
- lib/chef/knife/ninefold_image_list.rb
|
47
|
+
- lib/chef/knife/ninefold_server_create.rb
|
48
|
+
- lib/chef/knife/ninefold_server_delete.rb
|
49
|
+
- lib/chef/knife/ninefold_server_list.rb
|
50
|
+
- lib/knife-ninefold/version.rb
|
51
|
+
homepage:
|
52
|
+
licenses: []
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
requirements: []
|
70
|
+
rubyforge_project:
|
71
|
+
rubygems_version: 1.8.11
|
72
|
+
signing_key:
|
73
|
+
specification_version: 3
|
74
|
+
summary: Ninefold Support for Chef's Knife Command
|
75
|
+
test_files: []
|