knife-topo 0.0.3
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/LICENSE +201 -0
- data/README.md +308 -0
- data/knife-topo.gemspec +21 -0
- data/lib/chef/knife/topo/version.rb +5 -0
- data/lib/chef/knife/topo_bootstrap.rb +114 -0
- data/lib/chef/knife/topo_cookbook_create.rb +178 -0
- data/lib/chef/knife/topo_cookbook_upload.rb +84 -0
- data/lib/chef/knife/topo_create.rb +110 -0
- data/lib/chef/knife/topo_export.rb +137 -0
- data/lib/chef/knife/topo_import.rb +100 -0
- data/lib/chef/knife/topo_update.rb +110 -0
- data/lib/chef/knife/topology_helper.rb +280 -0
- data/test-repo/.chef/dummy.pem +27 -0
- data/test-repo/.chef/knife.rb +13 -0
- data/test-repo/Berksfile +4 -0
- data/test-repo/Instructions.txt +48 -0
- data/test-repo/Vagrantfile +67 -0
- data/test-repo/cookbooks/README.md +54 -0
- data/test-repo/cookbooks/testapp/CHANGELOG.md +10 -0
- data/test-repo/cookbooks/testapp/README.md +26 -0
- data/test-repo/cookbooks/testapp/files/default/index.html +13 -0
- data/test-repo/cookbooks/testapp/files/default/package.json +14 -0
- data/test-repo/cookbooks/testapp/files/default/server.js +42 -0
- data/test-repo/cookbooks/testapp/metadata.rb +9 -0
- data/test-repo/cookbooks/testapp/recipes/appserver.rb +8 -0
- data/test-repo/cookbooks/testapp/recipes/db.rb +9 -0
- data/test-repo/cookbooks/testapp/recipes/default.rb +11 -0
- data/test-repo/cookbooks/testapp/recipes/deploy.rb +50 -0
- data/test-repo/cookbooks/testapp/templates/default/nodejs.upstart.conf.erb +9 -0
- data/test-repo/multipletopology.json +117 -0
- data/test-repo/topology.json +99 -0
- metadata +78 -0
@@ -0,0 +1,110 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Christine Draper (<christine_draper@thirdwaveinsights.com>)
|
3
|
+
# Copyright:: Copyright (c) 2014 ThirdWave Insights LLC
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'chef/knife'
|
20
|
+
require_relative 'topo_cookbook_upload'
|
21
|
+
|
22
|
+
class Chef
|
23
|
+
class Knife
|
24
|
+
class TopoUpdate < Chef::Knife
|
25
|
+
|
26
|
+
deps do
|
27
|
+
Chef::Knife::TopoCookbookUpload.load_deps
|
28
|
+
end
|
29
|
+
|
30
|
+
banner "knife topo update [ TOPOLOGY ] (options)"
|
31
|
+
|
32
|
+
option :data_bag,
|
33
|
+
:short => '-D DATA_BAG',
|
34
|
+
:long => "--data-bag DATA_BAG",
|
35
|
+
:description => "The data bag the topologies are stored in"
|
36
|
+
|
37
|
+
# Make called command options available
|
38
|
+
self.options = Chef::Knife::TopoCookbookUpload.options.merge(self.options)
|
39
|
+
|
40
|
+
def initialize (args)
|
41
|
+
super
|
42
|
+
@topo_upload_args = initialize_cmd_args(args, [ 'topo', 'cookbook', 'upload', '' ])
|
43
|
+
|
44
|
+
# All called commands need to accept union of options
|
45
|
+
Chef::Knife::TopoCookbookUpload.options = options
|
46
|
+
end
|
47
|
+
|
48
|
+
def run
|
49
|
+
|
50
|
+
bag_name = topo_bag_name(config[:data_bag])
|
51
|
+
|
52
|
+
if !@name_args[0]
|
53
|
+
ui.confirm("Do you want to update all topologies in the #{bag_name} data bag", true, true)
|
54
|
+
end
|
55
|
+
|
56
|
+
topo_name = @name_args[0]
|
57
|
+
|
58
|
+
if topo_name
|
59
|
+
# update a specific topo
|
60
|
+
ui.info "Updating topology: #{topo_name} in data bag: #{bag_name}"
|
61
|
+
|
62
|
+
unless current_topo = load_from_server(bag_name, topo_name)
|
63
|
+
ui.fatal "Topology #{bag_name}/#{topo_name} does not exist on server - use 'knife topo create' first"
|
64
|
+
exit(1)
|
65
|
+
end
|
66
|
+
|
67
|
+
unless topo = load_from_file(bag_name, topo_name)
|
68
|
+
ui.info "No topology found in #{topologies_path}/#{bag_name}/#{topo_name}.json - exiting without action"
|
69
|
+
exit(0)
|
70
|
+
end
|
71
|
+
|
72
|
+
update_topo(topo)
|
73
|
+
|
74
|
+
else
|
75
|
+
# find all topologies from server then update them from file, skipping any that have no file
|
76
|
+
ui.info "Updating all topologies in data bag: #{bag_name}"
|
77
|
+
|
78
|
+
unless dbag = load_from_server(bag_name)
|
79
|
+
ui.fatal "Data bag #{bag_name} does not exist on server - use 'knife topo create' first"
|
80
|
+
exit(1)
|
81
|
+
end
|
82
|
+
|
83
|
+
dbag.keys.each do |topo_name|
|
84
|
+
|
85
|
+
topo = load_from_file(bag_name, topo_name)
|
86
|
+
if !topo
|
87
|
+
# do not update topologies that are not in the local workspace
|
88
|
+
ui.info("No topology file found in #{topologies_path}/#{bag_name}/#{topo_name}.json - skipping")
|
89
|
+
else
|
90
|
+
ui.info("Updating topology #{topo_name}")
|
91
|
+
update_topo(topo)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
ui.info "Updates done"
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
def update_topo(topo)
|
100
|
+
topo.save
|
101
|
+
@topo_upload_args[3] = topo['name']
|
102
|
+
upload_cookbooks(@topo_upload_args) if (!config[:no_upload])
|
103
|
+
create_or_update_nodes(topo)
|
104
|
+
end
|
105
|
+
|
106
|
+
include Chef::Knife::TopologyHelper
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,280 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Christine Draper (<christine_draper@thirdwaveinsights.com>)
|
3
|
+
# Copyright:: Copyright (c) 2014 ThirdWave Insights LLC
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'chef/data_bag'
|
20
|
+
require 'chef/encrypted_data_bag_item'
|
21
|
+
require 'chef/knife/core/object_loader'
|
22
|
+
|
23
|
+
class Chef
|
24
|
+
class Knife
|
25
|
+
module TopologyHelper
|
26
|
+
|
27
|
+
# load one or more topologies from file
|
28
|
+
def load_topologies(topology_file_path)
|
29
|
+
|
30
|
+
if ! topology_file_path.end_with?('.js', '.json')
|
31
|
+
show_usage
|
32
|
+
ui.fatal "TOPOLOGY_FILE must be a '.js' or '.json' file"
|
33
|
+
exit(1)
|
34
|
+
end
|
35
|
+
|
36
|
+
topologies = loader.object_from_file(topology_file_path)
|
37
|
+
topologies = [topologies] if !topologies.kind_of?(Array)
|
38
|
+
|
39
|
+
topologies
|
40
|
+
end
|
41
|
+
|
42
|
+
# create the topology data bag
|
43
|
+
def create_bag(bag_name)
|
44
|
+
# check that the name is valid
|
45
|
+
begin
|
46
|
+
Chef::DataBag.validate_name!(bag_name)
|
47
|
+
rescue Chef::Exceptions::InvalidDataBagName => e
|
48
|
+
ui.fatal(e.message)
|
49
|
+
exit(1)
|
50
|
+
end
|
51
|
+
|
52
|
+
# create the data bag
|
53
|
+
begin
|
54
|
+
data_bag = Chef::DataBag.new
|
55
|
+
data_bag.name(bag_name)
|
56
|
+
data_bag.create
|
57
|
+
ui.info("Created topology data bag [#{bag_name}]")
|
58
|
+
rescue Net::HTTPServerException => e
|
59
|
+
raise unless e.to_s =~ /^409/
|
60
|
+
data_bag = Chef::DataBag.load(bag_name)
|
61
|
+
ui.info("Topology data bag #{bag_name} already exists")
|
62
|
+
end
|
63
|
+
|
64
|
+
data_bag
|
65
|
+
end
|
66
|
+
|
67
|
+
# make sure the chef environment exists
|
68
|
+
def check_chef_env(chef_env_name)
|
69
|
+
|
70
|
+
if chef_env_name
|
71
|
+
begin
|
72
|
+
chef_env = Chef::Environment.load(chef_env_name)
|
73
|
+
rescue Net::HTTPServerException => e
|
74
|
+
raise unless e.to_s =~ /^404/
|
75
|
+
ui.info "Creating chef environment " + chef_env_name
|
76
|
+
chef_env = Chef::Environment.new()
|
77
|
+
chef_env.name(chef_env_name)
|
78
|
+
chef_env.create
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
chef_env
|
83
|
+
end
|
84
|
+
|
85
|
+
# Merges topology properties into nodes, returning the merged nodes
|
86
|
+
def merge_topo_properties(nodes, topo_hash)
|
87
|
+
|
88
|
+
if nodes
|
89
|
+
merged_nodes = nodes.clone
|
90
|
+
merged_nodes.each do |nodeprops|
|
91
|
+
|
92
|
+
nodeprops['chef_environment'] ||= topo_hash['chef_environment'] if topo_hash['chef_environment']
|
93
|
+
|
94
|
+
# merge in the topology tags
|
95
|
+
nodeprops['tags'] |= topo_hash['tags'] if topo_hash['tags']
|
96
|
+
|
97
|
+
normal_defaults = topo_hash['normal'] || {}
|
98
|
+
nodeprops['normal'] = normal_defaults.merge(nodeprops['normal'] || {})
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
merged_nodes
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
# Get nodes from the topology, create them and/or set their run lists
|
108
|
+
def create_or_update_nodes(topo)
|
109
|
+
|
110
|
+
topo_hash = topo.raw_data
|
111
|
+
nodes = merge_topo_properties(topo_hash['nodes'], topo_hash)
|
112
|
+
config[:disable_editing] = true
|
113
|
+
|
114
|
+
if nodes.length > 0
|
115
|
+
nodes.each do |updates|
|
116
|
+
node_name = updates['name']
|
117
|
+
begin
|
118
|
+
# load then update and save the node
|
119
|
+
node = Chef::Node.load(node_name)
|
120
|
+
if updated_values = update_node_with_values(node, updates)
|
121
|
+
ui.info "Updating #{updated_values.join(', ')} on node #{node.name}"
|
122
|
+
node.save
|
123
|
+
ui.output(format_for_display(node)) if config[:print_after]
|
124
|
+
else
|
125
|
+
ui.info "No updates found for node #{node.name}"
|
126
|
+
end
|
127
|
+
|
128
|
+
rescue Net::HTTPServerException => e
|
129
|
+
raise unless e.to_s =~ /^404/
|
130
|
+
# Create the node
|
131
|
+
node = Chef::Node.new
|
132
|
+
node.name(node_name)
|
133
|
+
update_node_with_values(node, updates)
|
134
|
+
create_object(node)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
else
|
138
|
+
ui.info "No nodes found for topology #{topo_hash.name}"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Make updates into the original node, returning the list of updated properties.
|
143
|
+
def update_node_with_values(node, updates)
|
144
|
+
updated_properties = []
|
145
|
+
|
146
|
+
if updates['run_list']
|
147
|
+
updated_run_list = RunList.new
|
148
|
+
updates['run_list'].each { |e| updated_run_list << e }
|
149
|
+
if (updated_run_list != node.run_list)
|
150
|
+
updated_properties << 'run_list'
|
151
|
+
node.run_list(*updated_run_list)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
new_chef_environment = updates['chef_environment']
|
156
|
+
if new_chef_environment && new_chef_environment != node.chef_environment
|
157
|
+
updated_properties << 'chef_environment'
|
158
|
+
node.chef_environment(new_chef_environment)
|
159
|
+
end
|
160
|
+
|
161
|
+
orig_num_tags = node.tags.length
|
162
|
+
updates['tags'] ||= [] # make sure tags are initialized
|
163
|
+
node.tag(*updates['tags'])
|
164
|
+
updated_properties << 'tags' if node.tags.length > orig_num_tags
|
165
|
+
|
166
|
+
normal_updates = updates['normal'] || {}
|
167
|
+
normal_updates.each do |key, value|
|
168
|
+
if (value != node.normal[key])
|
169
|
+
updated_properties << "normal.#{key}"
|
170
|
+
node.normal[key] = value
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# return false if no updates, else return array of property names
|
175
|
+
updated_properties.length > 0 && updated_properties
|
176
|
+
end
|
177
|
+
|
178
|
+
# Load a topology from local data bag item file
|
179
|
+
def load_from_file(bag_name, topo_name)
|
180
|
+
return unless topo_file = loader.find_file("#{topologies_path}", bag_name, topo_name + '.json')
|
181
|
+
|
182
|
+
item_data = loader.object_from_file(topo_file)
|
183
|
+
item_data = if use_encryption
|
184
|
+
secret = read_secret
|
185
|
+
Chef::EncryptedDataBagItem.encrypt_data_bag_item(item_data, secret)
|
186
|
+
else
|
187
|
+
item_data
|
188
|
+
end
|
189
|
+
item = Chef::DataBagItem.new
|
190
|
+
item.data_bag(bag_name)
|
191
|
+
item.raw_data = item_data
|
192
|
+
item
|
193
|
+
end
|
194
|
+
|
195
|
+
# read in the topology bag item
|
196
|
+
def load_from_server(bag_name, item_name = nil)
|
197
|
+
begin
|
198
|
+
if (item_name)
|
199
|
+
item = Chef::DataBagItem.load(bag_name, item_name)
|
200
|
+
item = Chef::EncryptedDataBagItem.new(item.raw_data, read_secret) if use_encryption
|
201
|
+
else
|
202
|
+
item = Chef::DataBag.load(bag_name)
|
203
|
+
end
|
204
|
+
rescue Net::HTTPServerException => e
|
205
|
+
raise unless e.to_s =~ /^404/
|
206
|
+
end
|
207
|
+
item
|
208
|
+
end
|
209
|
+
|
210
|
+
# Replace existing run list in a node
|
211
|
+
def set_run_list(node, entries)
|
212
|
+
node.run_list.run_list_items.clear
|
213
|
+
entries.each { |e| node.run_list << e }
|
214
|
+
end
|
215
|
+
|
216
|
+
# Name of the topology bag
|
217
|
+
def topo_bag_name(name=nil)
|
218
|
+
@topo_bag_name = name if (name)
|
219
|
+
@topo_bag_name ||= "topologies"
|
220
|
+
end
|
221
|
+
|
222
|
+
# Path for the topologies data bags.
|
223
|
+
# For now, use the standard data_bags path for our topologies bags
|
224
|
+
def topologies_path
|
225
|
+
@topologies_path ||= "data_bags"
|
226
|
+
end
|
227
|
+
|
228
|
+
# Loader to get data bag items from file
|
229
|
+
def loader
|
230
|
+
@loader ||= Knife::Core::ObjectLoader.new(DataBagItem, ui)
|
231
|
+
end
|
232
|
+
|
233
|
+
# Determine if the bag items are/should be encrypted on server
|
234
|
+
# NOTE: This option isnt currently enabled
|
235
|
+
def use_encryption
|
236
|
+
if config[:secret] && config[:secret_file]
|
237
|
+
ui.fatal("please specify only one of --secret, --secret-file")
|
238
|
+
exit(1)
|
239
|
+
end
|
240
|
+
config[:secret] || config[:secret_file]
|
241
|
+
end
|
242
|
+
|
243
|
+
# Return the secret key to encrypt/decrypt data bag items
|
244
|
+
def read_secret
|
245
|
+
if config[:secret]
|
246
|
+
config[:secret]
|
247
|
+
else
|
248
|
+
Chef::EncryptedDataBagItem.load_secret(config[:secret_file])
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
# initialize args for another knife command
|
253
|
+
def initialize_cmd_args(args, new_name_args)
|
254
|
+
args = args.dup
|
255
|
+
args.shift(2 + @name_args.length)
|
256
|
+
cmd_args = new_name_args + args
|
257
|
+
end
|
258
|
+
|
259
|
+
# run another knife command
|
260
|
+
def run_cmd(command_class, args)
|
261
|
+
command = command_class.new(args)
|
262
|
+
command.config[:config_file] = config[:config_file]
|
263
|
+
command.configure_chef
|
264
|
+
command.run
|
265
|
+
|
266
|
+
command
|
267
|
+
end
|
268
|
+
|
269
|
+
# upload cookbooks - will warn and continue if upload fails (e.g. may be frozen)
|
270
|
+
def upload_cookbooks(args)
|
271
|
+
begin
|
272
|
+
run_cmd(Chef::Knife::TopoCookbookUpload, args)
|
273
|
+
rescue Exception => e
|
274
|
+
raise if Chef::Config[:verbosity] == 2
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
2
|
+
MIIEogIBAAKCAQEAqZszg6n+ukMvore53ROFNQAAZhEfW0H9erLqC/4Go/lkRhwl
|
3
|
+
d/BOu3bexV2bQFh8Eqg/0VfP0/eOGx4pt6lOP1W20isWr0sGnf8DID2oB/Vi/NhS
|
4
|
+
+zfnos/TMXbJSvXryfpMUB6YKhraC645Q0zuBDHm+3fjGol6nND/tVWCW9h+og7d
|
5
|
+
WTZLOVUbbD949F7WBVEcbNp66e49AaZ5yYevVJtjCQRQQ1E9d+/WsMM0Nv24VEc2
|
6
|
+
oEmbH4U0/+g+WKiJB4m/IDJ4RXco3JtFNpkM/HeKHcc0Niw1A8aLVv5Bp3hYkEnh
|
7
|
+
VidA+H2nZ7IxNOzF3wzJAUwxmg89hC2X1t9WUQIDAQABAoIBAGCZrBKOrS3LfIMy
|
8
|
+
H6NiLdmNAa0gjXp9sHDFHHbuHTwhnFIuT8zrSvyM7L7+3KEehLRfrdF/MTjqY77g
|
9
|
+
RCR+QrniCPnVXttCYSd2CoK/e0flJJccYs8A/WaG9iPTIz0VqlFkxThQ5Jv+pThH
|
10
|
+
6AeD9oDfJ08M7oW7zeEpTKssY84JKE7iAPjBoRF8wMjJPbJB6HEDKPT6pPL9fyjF
|
11
|
+
+FkD01XxaI4Ip5vXsc0+Lckf9uItD5SP4CDcFVxFtU+4m/iJjBrUxeUDrzWCzOY4
|
12
|
+
SgfD9aJ3J79acQ4omtvD0iGUSu/4CwSpAyuw0qzBOS2tmYyaiz0EK2YGg3IbE9xz
|
13
|
+
jPjnj40CgYEA1ai6cb/9PBfF82sG6e23fie2odHN6Lt5Ex7AmCjGg7yVly1rLm7f
|
14
|
+
LxCA+bJfwyOmx7/rptECAFnQeahVcsLQ3KXDwm0IP8Ow60s83Tk0HNrejlIK7f5i
|
15
|
+
8PlvO7Z+bhbTqKDI12YuKJ74pBw4WCP7U4fmxWNryFj1/7o8gPgsqesCgYEAyzeZ
|
16
|
+
3lbya3Txl3gYhS5Ppeuqave/q1jcCYUmoTqCfyZxqQyCmuVpMN/S6zx/vTAlFqHK
|
17
|
+
OsE5v9GD+NuvfhXga4+9FH4nMdbdhYntHLSwgAW/WPShVsNM2WCibIZtkOoI3Bkl
|
18
|
+
wYQF+PZNGPmAChaEsE7oq6vavHD5DHeVmn3M1bMCgYBbLeZjJMutGXggqUwKCKiF
|
19
|
+
7ezCogZ9i4Pf5P/L75rIHXK5UWisKCSWsTRZWwYDAPPryruGNSvlem69fFj64KjB
|
20
|
+
gPxJvL4IeDrILxOKVR8oMT9I/Tos1qLis5AEq5zI3nT1Qah0Q+bu7uitIF3rP2/B
|
21
|
+
9f1Fv2f/1/cjaxbm8wIcgQKBgBx4t8gc6m3/vnF4VAcky+f1MrU17Na25m03CIiC
|
22
|
+
SBJEcpw6snm9NpWwZj6rBUKeYjPfixPcSpkDY7gUH2xM6FppkxYx7o/fCL5S6rOg
|
23
|
+
5TGqnHp8G7aqOjQig98snmE1SPR9WXrZYnTVHUwoeLXxHboN9C9JLqZENcB3aLBy
|
24
|
+
e6ZdAoGACeT2RLyEngm2XVcdNeiXbtwu8+qhoK4FHX5eFKmO2hm+xDo/601acaH+
|
25
|
+
LdFDMKfGevjqTCVS9ZD3SgELSk+KpAvXpVmOzXaX/n/eGCVOYxsWPEKhwpEUsIml
|
26
|
+
9rq1jU/phQw7627WvP8UbwMbNl1u1SDCJwFTFssVmZ3pDI4nth8=
|
27
|
+
-----END RSA PRIVATE KEY-----
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# See http://docs.opscode.com/config_rb_knife.html for more information on knife configuration options
|
2
|
+
|
3
|
+
current_dir = File.dirname(__FILE__)
|
4
|
+
log_level :info
|
5
|
+
log_location STDOUT
|
6
|
+
node_name "workstation"
|
7
|
+
client_key "#{current_dir}/dummy.pem"
|
8
|
+
validation_client_name "validator"
|
9
|
+
validation_key "#{current_dir}/dummy.pem"
|
10
|
+
chef_server_url "http://10.0.1.1:8889"
|
11
|
+
cache_type 'BasicFile'
|
12
|
+
cache_options( :path => "#{ENV['HOME']}/.chef/checksums" )
|
13
|
+
cookbook_path ["#{current_dir}/../cookbooks"]
|
data/test-repo/Berksfile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Assumptions for this demo: chefDK, Vagrant, VirtualBox and chef-zero
|
2
|
+
|
3
|
+
# chefDK can be obtained from:
|
4
|
+
http://www.getchef.com/downloads/chef-dk/
|
5
|
+
|
6
|
+
# vagrant can be installed from:
|
7
|
+
https://www.vagrantup.com/downloads.html
|
8
|
+
|
9
|
+
# VirtualBox can be obtained from:
|
10
|
+
https://www.virtualbox.org/wiki/Downloads
|
11
|
+
|
12
|
+
# If you have chefDK installed, you can use the embedded chef-zero
|
13
|
+
/opt/chefdk/embedded/bin/chef-zero
|
14
|
+
|
15
|
+
# or install it
|
16
|
+
sudo gem install chef-zero
|
17
|
+
|
18
|
+
# Copy test-repo into a working directory, either downloading it from github or copying it from the installed
|
19
|
+
# knife-topo gem. You can use
|
20
|
+
gem env
|
21
|
+
# to get the path to your gems and then
|
22
|
+
cp -R <path-to-gem>/knife-topo/test-repo ~
|
23
|
+
cd ~/test-repo
|
24
|
+
|
25
|
+
# From the test-repo, do the following to start the virtual machines on a private network using vagrant -
|
26
|
+
# Note: you may be prompted to select the network to bridge to
|
27
|
+
vagrant up
|
28
|
+
|
29
|
+
# Once the virtual machines are created, start chef-zero listening on the same private network:
|
30
|
+
chef-zero -H 10.0.1.1
|
31
|
+
|
32
|
+
# In another terminal, in test-repo:
|
33
|
+
berks install
|
34
|
+
berks upload
|
35
|
+
|
36
|
+
# To create and bootstrap the test1 topology
|
37
|
+
knife topo import exchange.json
|
38
|
+
knife topo create sys1_test test1
|
39
|
+
knife topo bootstrap sys1_test test1 -x vagrant -P vagrant --sudo
|
40
|
+
|
41
|
+
|
42
|
+
# To check the bootstrap has succeeded, browse to:
|
43
|
+
http://localhost:3031
|
44
|
+
# You should see a "Welcome" message
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
# vi: set ft=ruby :
|
3
|
+
|
4
|
+
# This Vagrantfile was inspired by Joshua Timberman's blog
|
5
|
+
# http://jtimberman.housepub.org/blog/2012/03/18/multivm-vagrantfile-for-chef/
|
6
|
+
|
7
|
+
#
|
8
|
+
# Vagrantfile for two-machine test topology. Runs with a private network
|
9
|
+
# and port forwarding from 3001 on appserver guest, to port 303n on host (i.e. 3031 for topo with id 1).
|
10
|
+
# ipaddresses are 10.0.1.2, 10.0.1.3 for dbserver, appserver.
|
11
|
+
|
12
|
+
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
|
13
|
+
VAGRANTFILE_API_VERSION = "2"
|
14
|
+
|
15
|
+
id = 1
|
16
|
+
qual = "0#{id}"
|
17
|
+
|
18
|
+
# Define the options for each node
|
19
|
+
nodes = {
|
20
|
+
:dbserver => {
|
21
|
+
:hostname => "dbserver#{qual}",
|
22
|
+
:ipaddress => "10.0.#{id}.2"
|
23
|
+
},
|
24
|
+
:appserver => {
|
25
|
+
:hostname => "appserver#{qual}",
|
26
|
+
:ipaddress => "10.0.#{id}.3",
|
27
|
+
:forwardports => [
|
28
|
+
{
|
29
|
+
:guest => 3001,
|
30
|
+
:host => (3030 + id)
|
31
|
+
}
|
32
|
+
]
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
37
|
+
|
38
|
+
# setup each node using config ("options") defined above
|
39
|
+
nodes.each do |node, options|
|
40
|
+
config.vm.define node do |node_config|
|
41
|
+
|
42
|
+
# setup networking using private network, with port forwarding where needed to access
|
43
|
+
# TODO how to let ip be optional in either case
|
44
|
+
net_type = ( options.has_key?(:public)) ? :public_network : :private_network
|
45
|
+
if options.has_key?(:public)
|
46
|
+
node_config.vm.network net_type, ip: options[:ipaddress]
|
47
|
+
else
|
48
|
+
node_config.vm.network net_type, ip: options[:ipaddress]
|
49
|
+
end
|
50
|
+
|
51
|
+
if options.has_key?(:forwardports)
|
52
|
+
options[:forwardports].each do |port|
|
53
|
+
node_config.vm.network :forwarded_port, guest: port[:guest], host: port[:host]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
node_config.vm.hostname = options[:hostname]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Setup the generic config across both servers
|
61
|
+
config.vm.box = "ubuntu64"
|
62
|
+
|
63
|
+
# The url from where the 'config.vm.box' box will be fetched if it
|
64
|
+
# doesn't already exist on the user's system.
|
65
|
+
config.vm.box_url = "http://files.vagrantup.com/precise64.box"
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
This directory contains the cookbooks used to configure systems in your infrastructure with Chef.
|
2
|
+
|
3
|
+
Knife needs to be configured to know where the cookbooks are located with the `cookbook_path` setting. If this is not set, then several cookbook operations will fail to work properly.
|
4
|
+
|
5
|
+
cookbook_path ["./cookbooks"]
|
6
|
+
|
7
|
+
This setting tells knife to look for the cookbooks directory in the present working directory. This means the knife cookbook subcommands need to be run in the `chef-repo` directory itself. To make sure that the cookbooks can be found elsewhere inside the repository, use an absolute path. This is a Ruby file, so something like the following can be used:
|
8
|
+
|
9
|
+
current_dir = File.dirname(__FILE__)
|
10
|
+
cookbook_path ["#{current_dir}/../cookbooks"]
|
11
|
+
|
12
|
+
Which will set `current_dir` to the location of the knife.rb file itself (e.g. `~/chef-repo/.chef/knife.rb`).
|
13
|
+
|
14
|
+
Configure knife to use your preferred copyright holder, email contact and license. Add the following lines to `.chef/knife.rb`.
|
15
|
+
|
16
|
+
cookbook_copyright "Example, Com."
|
17
|
+
cookbook_email "cookbooks@example.com"
|
18
|
+
cookbook_license "apachev2"
|
19
|
+
|
20
|
+
Supported values for `cookbook_license` are "apachev2", "mit","gplv2","gplv3", or "none". These settings are used to prefill comments in the default recipe, and the corresponding values in the metadata.rb. You are free to change the the comments in those files.
|
21
|
+
|
22
|
+
Create new cookbooks in this directory with Knife.
|
23
|
+
|
24
|
+
knife cookbook create COOKBOOK
|
25
|
+
|
26
|
+
This will create all the cookbook directory components. You don't need to use them all, and can delete the ones you don't need. It also creates a README file, metadata.rb and default recipe.
|
27
|
+
|
28
|
+
You can also download cookbooks directly from the Opscode Cookbook Site. There are two subcommands to help with this depending on what your preference is.
|
29
|
+
|
30
|
+
The first and recommended method is to use a vendor branch if you're using Git. This is automatically handled with Knife.
|
31
|
+
|
32
|
+
knife cookbook site install COOKBOOK
|
33
|
+
|
34
|
+
This will:
|
35
|
+
|
36
|
+
* Download the cookbook tarball from cookbooks.opscode.com.
|
37
|
+
* Ensure its on the git master branch.
|
38
|
+
* Checks for an existing vendor branch, and creates if it doesn't.
|
39
|
+
* Checks out the vendor branch (chef-vendor-COOKBOOK).
|
40
|
+
* Removes the existing (old) version.
|
41
|
+
* Untars the cookbook tarball it downloaded in the first step.
|
42
|
+
* Adds the cookbook files to the git index and commits.
|
43
|
+
* Creates a tag for the version downloaded.
|
44
|
+
* Checks out the master branch again.
|
45
|
+
* Merges the cookbook into master.
|
46
|
+
* Repeats the above for all the cookbooks dependencies, downloading them from the community site
|
47
|
+
|
48
|
+
The last step will ensure that any local changes or modifications you have made to the cookbook are preserved, so you can keep your changes through upstream updates.
|
49
|
+
|
50
|
+
If you're not using Git, use the site download subcommand to download the tarball.
|
51
|
+
|
52
|
+
knife cookbook site download COOKBOOK
|
53
|
+
|
54
|
+
This creates the COOKBOOK.tar.gz from in the current directory (e.g., `~/chef-repo`). We recommend following a workflow similar to the above for your version control tool.
|
@@ -0,0 +1,26 @@
|
|
1
|
+
Test Application Cookbook
|
2
|
+
=========================
|
3
|
+
A simple nodejs application that puts up a welcome page.
|
4
|
+
|
5
|
+
Requirements
|
6
|
+
------------
|
7
|
+
Tested on Ubuntu 12.04 LTS.
|
8
|
+
|
9
|
+
#### packages
|
10
|
+
- `nodejs` - The test application is a nodejs application
|
11
|
+
- ` mongodb` - In the future, the test application will have a connection to a database
|
12
|
+
|
13
|
+
Attributes
|
14
|
+
----------
|
15
|
+
None
|
16
|
+
|
17
|
+
|
18
|
+
Recipes
|
19
|
+
-------
|
20
|
+
#### testapp::default
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
License and Authors
|
25
|
+
-------------------
|
26
|
+
Authors: Christine Draper, ThirdWave Insights, LLC
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
6
|
+
<title>YPO Test Application</title>
|
7
|
+
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
<p> Welcome ! You can find the knife topo plugin on Github:</p>
|
11
|
+
<a href="https://github.com">https://github.com/thirdwaveinsights/knife-topo</a>
|
12
|
+
</body>
|
13
|
+
</html>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
{
|
2
|
+
"name": "testapp",
|
3
|
+
"description": "A dummy application for testing knife-topo",
|
4
|
+
"author": "ThirdWave Insights LLC <contact@thirdwaveinsights.com>",
|
5
|
+
"version": "0.0.1",
|
6
|
+
"private": true,
|
7
|
+
"main": "server.js",
|
8
|
+
"dependencies": {
|
9
|
+
"express": "3.3.4",
|
10
|
+
"ejs": "0.8.4",
|
11
|
+
"connect": "2.8.4"
|
12
|
+
},
|
13
|
+
"engine": "node 0.10.15"
|
14
|
+
}
|