knife-ninefold 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|