podnix 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.
@@ -0,0 +1,375 @@
1
+ # Copyright:: Copyright (c) 2012, 2013 Megam Systems
2
+ # License:: Apache License, Version 2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ require 'hashie'
17
+ module Podnix
18
+ class Node
19
+ # Each notify entry is a resource/action pair, modeled as an
20
+ # Struct with a #resource and #action member
21
+ =begin
22
+ def self.hash_tree
23
+ Hash.new do |hash, key|
24
+ hash[key] = hash_tree
25
+ end
26
+ end
27
+ =end
28
+
29
+ def initialize
30
+ @id = nil
31
+ @node_name = nil
32
+ @accounts_id = nil
33
+ @node_type = nil
34
+ @req_type = nil
35
+ @status=nil
36
+ @noofinstances=0
37
+ @request ={}
38
+ @predefs={}
39
+ @some_msg = {}
40
+ #@command = self.class.hash_tree
41
+ @command = Hashie::Mash.new
42
+ @appdefnsid = nil
43
+ @boltdefnsid = nil
44
+ @appdefns = {}
45
+ @boltdefns = {}
46
+ @created_at = nil
47
+ end
48
+ def node
49
+ self
50
+ end
51
+
52
+ def podnix_rest
53
+ options = { :email => Megam::Config[:email], :api_key => Megam::Config[:api_key]}
54
+ Megam::API.new(options)
55
+ end
56
+
57
+ def node_name(arg=nil)
58
+ if arg != nil
59
+ @node_name = arg
60
+ else
61
+ @node_name
62
+ end
63
+ end
64
+
65
+ def noofinstances(arg=nil)
66
+ if arg != nil
67
+ @noofinstances = arg
68
+ else
69
+ @noofinstances
70
+ end
71
+ end
72
+
73
+ def command(arg=nil)
74
+ if arg != nil
75
+ @command = arg
76
+ else
77
+ @command
78
+ end
79
+ end
80
+
81
+ def id(arg=nil)
82
+ if arg != nil
83
+ @id = arg
84
+ else
85
+ @id
86
+ end
87
+ end
88
+
89
+ def accounts_id(arg=nil)
90
+ if arg != nil
91
+ @accounts_id = arg
92
+ else
93
+ @accounts_id
94
+ end
95
+ end
96
+
97
+ def node_type(arg=nil)
98
+ if arg != nil
99
+ @node_type = arg
100
+ else
101
+ @node_type
102
+ end
103
+ end
104
+
105
+ def req_type(arg=nil)
106
+ if arg != nil
107
+ @req_type = arg
108
+ else
109
+ @req_type
110
+ end
111
+ end
112
+
113
+ def status(arg=nil)
114
+ if arg != nil
115
+ @status = arg
116
+ else
117
+ @status
118
+ end
119
+ end
120
+
121
+ def request(arg=nil)
122
+ if arg != nil
123
+ @request = arg
124
+ else
125
+ @request
126
+ end
127
+ end
128
+
129
+ def predefs(arg=nil)
130
+ if arg != nil
131
+ @predefs = arg
132
+ else
133
+ @predefs
134
+ end
135
+ end
136
+
137
+ def appdefns(arg=nil)
138
+ if arg != nil
139
+ @appdefns = arg
140
+ else
141
+ @appdefns
142
+ end
143
+ end
144
+
145
+ def boltdefns(arg=nil)
146
+ if arg != nil
147
+ @boltdefns = arg
148
+ else
149
+ @boltdefns
150
+ end
151
+ end
152
+ def appdefnsid(arg=nil)
153
+ if arg != nil
154
+ @appdefnsid = arg
155
+ else
156
+ @appdefnsid
157
+ end
158
+ end
159
+
160
+ def boltdefnsid(arg=nil)
161
+ if arg != nil
162
+ @boltdefnsid = arg
163
+ else
164
+ @boltdefnsid
165
+ end
166
+ end
167
+
168
+ def created_at(arg=nil)
169
+ if arg != nil
170
+ @created_at = arg
171
+ else
172
+ @created_at
173
+ end
174
+ end
175
+
176
+ def some_msg(arg=nil)
177
+ if arg != nil
178
+ @some_msg = arg
179
+ else
180
+ @some_msg
181
+ end
182
+ end
183
+
184
+ def error?
185
+ crocked = true if (some_msg.has_key?(:msg_type) && some_msg[:msg_type] == "error")
186
+ end
187
+
188
+ # Transform the ruby obj -> to a Hash
189
+ def to_hash
190
+ index_hash = Hash.new
191
+ index_hash["json_claz"] = self.class.name
192
+ index_hash["id"] = id
193
+ index_hash["node_name"] = node_name
194
+ index_hash["accounts_id"] = accounts_id
195
+ index_hash["node_type"] = node_type
196
+ index_hash["req_type"] = req_type
197
+ index_hash["status"] = status
198
+ index_hash["command"] = command
199
+ index_hash["request"] = request
200
+ index_hash["predefs"] = predefs
201
+ index_hash["appdefns"] = appdefns
202
+ index_hash["boltdefns"] = boltdefns
203
+ index_hash["some_msg"] = some_msg
204
+ index_hash["noofinstances"] = noofinstances.to_i
205
+ index_hash["appdefnsid"] = appdefnsid
206
+ index_hash["boltdefnsid"] = boltdefnsid
207
+ index_hash["created_at"] = created_at
208
+ index_hash
209
+ end
210
+
211
+ # Serialize this object as a hash: called from JsonCompat.
212
+ # Verify if this called from JsonCompat during testing.
213
+ def to_json(*a)
214
+ for_json.to_json(*a)
215
+ end
216
+
217
+ def for_json
218
+ result = {
219
+ "id" => id,
220
+ "node_name" => node_name,
221
+ "accounts_id" => accounts_id,
222
+ "node_type" => node_type,
223
+ "req_type" => req_type,
224
+ "status" => status,
225
+ "request" => request,
226
+ "predefs" => predefs,
227
+ "appdefns" => appdefns,
228
+ "boltdefns" => boltdefns,
229
+ "appdefnsid" => appdefnsid,
230
+ "boltdefnsid" => boltdefnsid,
231
+ "noofinstances" => noofinstances,
232
+ "created_at" => created_at
233
+ }
234
+ result
235
+ end
236
+
237
+ # Create a Megam::Node from NodeResult-JSON
238
+ #
239
+ #[{
240
+ #"id":"NOD362212018897289216",
241
+ #"accounts_id":"ACT362211962353876992",
242
+ #"json_claz":"Megam::Node",
243
+ #"request":{
244
+ #"req_id":"NOD362212018897289216",
245
+ #"command":"commands"
246
+ #},
247
+ #"predefs":{
248
+ #"name":"",
249
+ #"scm":"",
250
+ #"war":"",
251
+ #"db":"",
252
+ #"queue":""
253
+ #}
254
+ #}]
255
+ #
256
+ def self.json_create(o)
257
+ node = new
258
+ node.id(o["id"]) if o.has_key?("id")
259
+ node.node_name(o["node_name"]) if o.has_key?("node_name")
260
+ node.accounts_id(o["accounts_id"]) if o.has_key?("accounts_id")
261
+ node.node_type(o["node_type"]) if o.has_key?("node_type")
262
+ node.req_type(o["req_type"]) if o.has_key?("req_type")
263
+ node.status(o["status"]) if o.has_key?("status")
264
+ node.appdefnsid(o["appdefnsid"]) if o.has_key?("appdefnsid")
265
+ node.boltdefnsid(o["boltdefnsid"]) if o.has_key?("boltdefnsid")
266
+ node.noofinstances(o["noofinstances"]) if o.has_key?("noofinstances")
267
+ node.created_at(o["created_at"]) if o.has_key?("created_at")
268
+ #requests
269
+ oq = o["request"]
270
+ node.request[:req_id] = oq["req_id"] if oq && oq.has_key?("req_id")
271
+ node.request[:req_type] = oq["req_type"] if oq && oq.has_key?("req_type")
272
+ node.request[:command] = oq["command"] if oq && oq.has_key?("command")
273
+
274
+ #Command
275
+ =begin
276
+ node.command[:systemprovider][:provider][:prov] = oc["systemprovider"]["provider"]["prov"]
277
+ node.command[:compute][:cctype] = oc["compute"]["cctype"]
278
+ node.command[:compute][:cc][:groups] = oc["compute"]["cc"]["groups"]
279
+ node.command[:compute][:cc][:image] = oc["compute"]["cc"]["image"]
280
+ node.command[:compute][:cc][:flavor] = oc["compute"]["cc"]["flavor"]
281
+ node.command[:compute][:access][:ssh_key] = oc["compute"]["access"]["ssh_key"]
282
+ node.command[:compute][:access][:identity_file] = oc["compute"]["access"]["identity_file"]
283
+ node.command[:compute][:access][:ssh_user] = oc["compute"]["access"]["ssh_user"]
284
+ node.command[:cloudtool][:chef][:command] = oc["cloudtool"]["chef"]["command"]
285
+ node.command[:cloudtool][:chef][:plugin] = oc["cloudtool"]["chef"]["plugin"]
286
+ node.command[:cloudtool][:chef][:run_list] = oc["cloudtool"]["chef"]["run_list"]
287
+ node.command[:cloudtool][:chef][:name] = oc["cloudtool"]["chef"]["name"]
288
+ =end
289
+ #predef
290
+ op = o["predefs"]
291
+ node.predefs[:name] = op["name"] if op && op.has_key?("name")
292
+ node.predefs[:scm] = op["scm"] if op && op.has_key?("scm")
293
+ node.predefs[:war]= op["war"] if op && op.has_key?("war")
294
+ node.predefs[:db] = op["db"] if op && op.has_key?("db")
295
+ node.predefs[:queue] = op["queue"] if op && op.has_key?("queue")
296
+
297
+ #APP DEFINITIONS
298
+ op = o["appdefns"]
299
+ node.appdefns[:timetokill] = op["timetokill"] if op && op.has_key?("timetokill")
300
+ node.appdefns[:metered] = op["metered"] if op && op.has_key?("metered")
301
+ node.appdefns[:logging]= op["logging"] if op && op.has_key?("logging")
302
+ node.appdefns[:runtime_exec] = op["runtime_exec"] if op && op.has_key?("runtime_exec")
303
+
304
+ #BOLT DEFINITIONS
305
+ op = o["boltdefns"]
306
+ node.boltdefns[:username] = op["username"] if op && op.has_key?("username")
307
+ node.boltdefns[:apikey] = op["apikey"] if op && op.has_key?("apikey")
308
+ node.boltdefns[:store_name]= op["store_name"] if op && op.has_key?("store_name")
309
+ node.boltdefns[:url] = op["url"] if op && op.has_key?("url")
310
+ node.boltdefns[:timetokill] = op["timetokill"] if op && op.has_key?("timetokill")
311
+ node.boltdefns[:metered] = op["metered"] if op && op.has_key?("metered")
312
+ node.boltdefns[:logging]= op["logging"] if op && op.has_key?("logging")
313
+ node.boltdefns[:runtime_exec] = op["runtime_exec"] if op && op.has_key?("runtime_exec")
314
+
315
+ #success or error
316
+ node.some_msg[:code] = o["code"] if o.has_key?("code")
317
+ node.some_msg[:msg_type] = o["msg_type"] if o.has_key?("msg_type")
318
+ node.some_msg[:msg]= o["msg"] if o.has_key?("msg")
319
+ node.some_msg[:links] = o["links"] if o.has_key?("links")
320
+
321
+ node
322
+ end
323
+
324
+ def self.from_hash(o)
325
+ node = self.new()
326
+ node.from_hash(o)
327
+ node
328
+ end
329
+
330
+ def from_hash(o)
331
+ @node_name = o["node_name"] if o.has_key?("node_name")
332
+ @command = o["command"] if o.has_key?("command")
333
+ @id = o["id"] if o.has_key?("id")
334
+ @accounts_id = o["accounts_id"] if o.has_key?("accounts_id")
335
+ @node_type = o["node_type"] if o.has_key?("node_type")
336
+ @req_type = o["req_type"] if o.has_key?("req_type")
337
+ @request = o["request"] if o.has_key?("request")
338
+ @predefs = o["predefs"] if o.has_key?("predefs")
339
+ @appdefns = o["appdefns"] if o.has_key?("appdefns")
340
+ @boltdefns = o["boltdefns"] if o.has_key?("boltdefns")
341
+ @appdefnsid = o["appdefnsid"] if o.has_key?("appdefnsid")
342
+ @boltdefnsid = o["boltdefnsid"] if o.has_key?("boltdefnsid")
343
+ @noofinstances = o["noofinstances"] if o.has_key?("noofinstances")
344
+ @created_at = o["created_at"] if o.has_key?("created_at")
345
+ self
346
+ end
347
+
348
+ def self.create(o)
349
+ acct = from_hash(o)
350
+ acct.create
351
+ end
352
+
353
+ # Create the node via the REST API
354
+ def create
355
+ podnix_rest.post_node(to_hash)
356
+ end
357
+
358
+ # Load a account by email_p
359
+ def self.show(node_name)
360
+ node = self.new()
361
+ node.podnix_rest.get_node(node_name)
362
+ end
363
+
364
+ def self.list
365
+ node = self.new()
366
+ node.podnix_rest.get_nodes
367
+ end
368
+
369
+ def to_s
370
+ Podnix::Stuff.styled_hash(to_hash)
371
+ #"---> Megam::Account:[error=#{error?}]\n"+
372
+ end
373
+
374
+ end
375
+ end
@@ -0,0 +1,166 @@
1
+ # Copyright:: Copyright (c) 2012, 2013 Megam Systems
2
+ # License:: Apache License, Version 2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ module Podnix
17
+ class NodeCollection
18
+ include Enumerable
19
+
20
+
21
+ attr_reader :iterator
22
+ def initialize
23
+ @nodes = Array.new
24
+ @nodes_by_name = Hash.new
25
+ @insert_after_idx = nil
26
+ end
27
+
28
+ def all_nodes
29
+ @nodes
30
+ end
31
+
32
+ def [](index)
33
+ @nodes[index]
34
+ end
35
+
36
+ def []=(index, arg)
37
+ is_megam_node(arg)
38
+ @nodes[index] = arg
39
+ @nodes_by_name[arg.node_name] = index
40
+ end
41
+
42
+ def <<(*args)
43
+ args.flatten.each do |a|
44
+ is_megam_node(a)
45
+ @nodes << a
46
+ @nodes_by_name[a.node_name] = @nodes.length - 1
47
+ end
48
+ self
49
+ end
50
+
51
+ # 'push' is an alias method to <<
52
+ alias_method :push, :<<
53
+
54
+ def insert(node)
55
+ is_megam_node(node)
56
+ if @insert_after_idx
57
+ # in the middle of executing a run, so any nodes inserted now should
58
+ # be placed after the most recent addition done by the currently executing
59
+ # node
60
+ @nodes.insert(@insert_after_idx + 1, node)
61
+ # update name -> location mappings and register new node
62
+ @nodes_by_name.each_key do |key|
63
+ @nodes_by_name[key] += 1 if @nodes_by_name[key] > @insert_after_idx
64
+ end
65
+ @nodes_by_name[node.node_name] = @insert_after_idx + 1
66
+ @insert_after_idx += 1
67
+ else
68
+ @nodes << node
69
+ @nodes_by_name[node.node_name] = @nodes.length - 1
70
+ end
71
+ end
72
+
73
+ def each
74
+ @nodes.each do |node|
75
+ yield node
76
+ end
77
+ end
78
+
79
+ def each_index
80
+ @nodes.each_index do |i|
81
+ yield i
82
+ end
83
+ end
84
+
85
+ def empty?
86
+ @nodes.empty?
87
+ end
88
+
89
+ def lookup(node)
90
+ lookup_by = nil
91
+ if node.kind_of?(Megam::Node)
92
+ lookup_by = node.node_name
93
+ elsif node.kind_of?(String)
94
+ lookup_by = node
95
+ else
96
+ raise ArgumentError, "Must pass a Megam::Node or String to lookup"
97
+ end
98
+ res = @nodes_by_name[lookup_by]
99
+ unless res
100
+ raise ArgumentError, "Cannot find a node matching #{lookup_by} (did you define it first?)"
101
+ end
102
+ @nodes[res]
103
+ end
104
+
105
+ # Transform the ruby obj -> to a Hash
106
+ def to_hash
107
+ index_hash = Hash.new
108
+ self.each do |node|
109
+ index_hash[node.node_name] = node.to_s
110
+ end
111
+ index_hash
112
+ end
113
+
114
+ # Serialize this object as a hash: called from JsonCompat.
115
+ # Verify if this called from JsonCompat during testing.
116
+ def to_json(*a)
117
+ for_json.to_json(*a)
118
+ end
119
+
120
+
121
+ =begin
122
+ ["json_claz":"Megam::NodeCollection",{
123
+ "id":"NOD362428315933343744",
124
+ "accounts_id":"ACT362211963352121344",
125
+ "json_claz":"Megam::Node",
126
+ "request":{
127
+ "req_id":"NOD362428315933343744",
128
+ "command":"commands"
129
+ },
130
+ "predefs":{
131
+ "name":"",
132
+ "scm":"",
133
+ "war":"",
134
+ "db":"",
135
+ "queue":""
136
+ }
137
+ }]
138
+ =end
139
+ def self.json_create(o)
140
+ collection = self.new()
141
+ o["results"].each do |nodes_list|
142
+ nodes_array = nodes_list.kind_of?(Array) ? nodes_list : [ nodes_list ]
143
+ nodes_array.each do |node|
144
+ collection.insert(node)
145
+ end
146
+ end
147
+ collection
148
+ end
149
+
150
+ private
151
+
152
+
153
+
154
+ def is_megam_node(arg)
155
+ unless arg.kind_of?(Megam::Node)
156
+ raise ArgumentError, "Members must be Megam::Node's"
157
+ end
158
+ true
159
+ end
160
+
161
+ def to_s
162
+ Podnix::Stuff.styled_hash(to_hash)
163
+ end
164
+
165
+ end
166
+ end
@@ -0,0 +1,69 @@
1
+ #
2
+ # License:: Apache License, Version 2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ module Podnix
17
+ module Stuff
18
+ extend self
19
+ def has_git?
20
+ %x{ git --version }
21
+ $?.success?
22
+ end
23
+
24
+ def git(args)
25
+ return "" unless has_git?
26
+ flattened_args = [args].flatten.compact.join(" ")
27
+ %x{ git #{flattened_args} 2>&1 }.strip
28
+ end
29
+
30
+ def time_ago(since)
31
+ if since.is_a?(String)
32
+ since = Time.parse(since)
33
+ end
34
+
35
+ elapsed = Time.now - since
36
+
37
+ message = since.strftime("%Y/%m/%d %H:%M:%S")
38
+ if elapsed <= 60
39
+ message << " (~ #{elapsed.floor}s ago)"
40
+ elsif elapsed <= (60 * 60)
41
+ message << " (~ #{(elapsed / 60).floor}m ago)"
42
+ elsif elapsed <= (60 * 60 * 25)
43
+ message << " (~ #{(elapsed / 60 / 60).floor}h ago)"
44
+ end
45
+ message
46
+ end
47
+
48
+ def spinner(ticks)
49
+ %w(/ - \\ |)[ticks % 4]
50
+ end
51
+
52
+ def launchy(message, url)
53
+ action(message) do
54
+ require("launchy")
55
+ launchy = Launchy.open(url)
56
+ if launchy.respond_to?(:join)
57
+ launchy.join
58
+ end
59
+ end
60
+ end
61
+
62
+ #
63
+ #left justified keyed hash with newlines.
64
+ def styled_hash(hash)
65
+ hash.map{|k,v| "#{k.ljust(15)}=#{v}"}.join("\n")
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,88 @@
1
+ #
2
+ # License:: Apache License, Version 2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ module Podnix
17
+ class Text
18
+
19
+ attr_reader :stdout
20
+ attr_reader :stderr
21
+ attr_reader :stdin
22
+ attr_reader :config
23
+ def initialize(stdout, stderr, stdin, config)
24
+ @stdout, @stderr, @stdin, @config = stdout, stderr, stdin, config
25
+ end
26
+
27
+ def highline
28
+ @highline ||= begin
29
+ require 'highline'
30
+ HighLine.new
31
+ end
32
+ end
33
+
34
+ def msg(message)
35
+ stdout.puts message
36
+ end
37
+
38
+ # Prints a message to stdout. Aliased as +info+ for compatibility with
39
+ # the logger API.
40
+
41
+ def info(message)
42
+ stdout.puts("#{color('INFO:', :green, :bold)} #{message}")
43
+ end
44
+
45
+ # Prints a msg to stderr. Used for warn, error, and fatal.
46
+ def err(message)
47
+ stderr.puts message
48
+ end
49
+
50
+ # Print a warning message
51
+ def warn(message)
52
+ err("#{color('WARNING:', :yellow, :bold)} #{message}")
53
+ end
54
+
55
+ # Print an error message
56
+ def error(message)
57
+ err("#{color('ERROR:', :red, :bold)} #{message}")
58
+ end
59
+
60
+ # Print a message describing a fatal error.
61
+ def fatal(message)
62
+ err("#{color('FATAL:', :red, :bold)} #{message}")
63
+ end
64
+
65
+ def color(string, *colors)
66
+ if color?
67
+ highline.color(string, *colors)
68
+ else
69
+ string
70
+ end
71
+ end
72
+
73
+ # Should colored output be used ?. When output is not to a
74
+ # terminal, colored output is never used
75
+ def color?
76
+ stdout.tty?
77
+ end
78
+
79
+ def list(*args)
80
+ highline.list(*args)
81
+ end
82
+
83
+ def pretty_print(data)
84
+ stdout.puts data
85
+ end
86
+
87
+ end
88
+ end
data/lib/podnix.rb ADDED
@@ -0,0 +1 @@
1
+ require(File.join(File.dirname(__FILE__), "podnix", "api"))