lita-rundeck 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 920881268d3717f0f643458c23cfb151436a1348
4
- data.tar.gz: baac69e1fa774f74ef82a5855f64252d3afc894c
3
+ metadata.gz: e5fe181cc70a8be965758bb306c00a5dfddfe966
4
+ data.tar.gz: 68259387a4d5cc02522e2c0117fa92bc12942c26
5
5
  SHA512:
6
- metadata.gz: adae124046d4cf97122a2ec8205de39698494d8d403b3e9041915f2bccf10f172e38d5cbc9c5e79d8851b038024e9ec9afb5569cfb47942717de130e28b14b3c
7
- data.tar.gz: 7628d6080c38058e30c70f50164552d8161c472b7958215348a0accefba1498f7c11e816e880742f93d77a0c9509235b629d329a43f26283e7c1c9896d3913a4
6
+ metadata.gz: 337cb78204675edeb677679fa9819d4d0363c29a3712350c1f5ea614704dedef56f5455e8334c048e6af56c9fe777f354f296060f67f756654913e576ef01fa1
7
+ data.tar.gz: 2aafc6f0e73291c05f35d6456841a325b65ca48093388ed6eac73221b7f46b19a13c640083e751d1771745aef04f4884ac62f511aa54fbd0a9c99b311cb70c3f
data/README.md CHANGED
@@ -38,23 +38,44 @@ end
38
38
 
39
39
  ### Run
40
40
 
41
- Start a job execution
41
+ Start a job execution. Optionally, have Lita return part or all of the output log to the channel when complete.
42
+
43
+ Syntax:
44
+ ```
45
+ rundeck run ALIAS|--project NAME --job NAME [--options KEY=VALUE,KEY=VALUE] [--report all|NUMBER]
46
+ ```
47
+
48
+ * Pass either an alias name or `--project` AND `--name` to execute the job
49
+ * Optionally, pass Job options (defined in rundeck itself) as key/value pairs delimited by a comma
50
+ * Finally, add `--report` with the string `all` to return the entirety of the log output to the channel once the job is complete. (Note Lita won't begin checking for job completion until the average duration of the job is complete.) You can also limit the output reported back to the channel. To do this, give the `--report` option an integer representing the number of lines to return from the end of the log.
51
+
52
+ Examples:
42
53
 
43
54
  ```
44
55
  Lita > lita rundeck run aliasfoo
45
- Execution 297 is running
56
+ Execution 285 is running. Average job duration is 1.717 seconds.
46
57
 
47
58
  Lita > rundeck run aliasfoo --options SECONDS=60
48
- Execution 298 is running
59
+ Execution 286 is running. Average job duration is 1.717 seconds.
49
60
 
50
61
  Lita > rundeck run --project Litatest --job dateoutput
51
- Execution 299 is running
62
+ Execution 287 is running. Average job duration is 1.717 seconds.
52
63
 
53
64
  Lita > rundeck run --project Litatest --job dateoutput --options SECONDS=60
54
- Execution 300 is running
65
+ Execution 288 is running. Average job duration is 1.717 seconds.
55
66
 
56
67
  Lita > rundeck run --project Litatest --job dateoutput --options SECONDS=60,FORMAT=iso8601
57
- Execution 301 is running
68
+ Execution 289 is running. Average job duration is 1.717 seconds.
69
+
70
+ Lita > rundeck run --project Litatest --job dateoutput --options SECONDS=60,FORMAT=iso8601 --report 5
71
+ Execution 289 is running. Average job duration is 1.717 seconds.
72
+ Execution 289 output:
73
+ 18:18:27 26 Sat May 9 18:18:27 UTC 2015
74
+ 18:18:28 27 Sat May 9 18:18:28 UTC 2015
75
+ 18:18:29 28 Sat May 9 18:18:29 UTC 2015
76
+ 18:18:30 29 Sat May 9 18:18:30 UTC 2015
77
+ 18:18:31 30 Sat May 9 18:18:31 UTC 2015
78
+ Execution 289 is complete (took 30.49s)
58
79
  ```
59
80
 
60
81
  * Users must be [added by a Lita admin](http://docs.lita.io/getting-started/usage/#authorization-groups) to the rundeck_users group to execute jobs
@@ -109,6 +130,40 @@ Lita > lita rundeck running
109
130
  297 running Shell User [Litatest] dateoutput SECONDS:60 start:2014-08-16T05:46:32Z
110
131
  ```
111
132
 
133
+ ### Output
134
+
135
+ List log output for given execution (showing last 10 lines, by default):
136
+
137
+ ```
138
+ Lita > lita output 5
139
+ Execution 5 output:
140
+ 23:16:30 Text of line 1
141
+ 23:16:31 Text of line 2
142
+ 23:16:32 Text of line 3
143
+ 23:16:33 Text of line 4
144
+ 23:16:34 Text of line 5
145
+ 23:16:35 Text of line 6
146
+ 23:16:36 Text of line 7
147
+ 23:16:37 Text of line 8
148
+ 23:16:38 Text of line 9
149
+ 23:16:39 Text of line 10
150
+ Execution 5 is complete (took 10.348s)
151
+ EOF
152
+ ```
153
+
154
+ Optionally, take an extra integer for the number lines to return:
155
+
156
+ ```
157
+ Lita > rundeck output 5 5
158
+ Execution 5 output:
159
+ 23:16:35 Text of line 6
160
+ 23:16:36 Text of line 7
161
+ 23:16:37 Text of line 8
162
+ 23:16:38 Text of line 9
163
+ 23:16:39 Text of line 10
164
+ Execution 5 is complete (took 10.348s)
165
+ ```
166
+
112
167
  ### Options
113
168
 
114
169
  List options for a job in detail
@@ -25,6 +25,11 @@ module Lita
25
25
  t("help.exec_key") => t("help.exec_value")
26
26
  }
27
27
 
28
+ route /rundeck output (\d+)(?: (\d+)?)?/i,
29
+ :output, command: true, help: {
30
+ t("help.output_key") => t("help.output_value")
31
+ }
32
+
28
33
  route /rundeck running(?: (\d+)?)?/i,
29
34
  :running, command: true, help: {
30
35
  t("help.running_key") => t("help.running_value")
@@ -44,9 +49,6 @@ module Lita
44
49
  },
45
50
  job: {
46
51
  short: "j"
47
- },
48
- options: {
49
- short: "o"
50
52
  }
51
53
  },
52
54
  help: {
@@ -70,6 +72,9 @@ module Lita
70
72
  },
71
73
  options: {
72
74
  short: "o"
75
+ },
76
+ report: {
77
+ short: "r"
73
78
  }
74
79
  },
75
80
  help: {
@@ -100,7 +105,10 @@ module Lita
100
105
 
101
106
  def info(response)
102
107
  text = []
103
- text.push(client.info)
108
+ output = client.info
109
+ return unless output
110
+
111
+ text.push(output)
104
112
  if users
105
113
  text.push(t("info.users_allowed") +
106
114
  users.map{ |u| u.name }.join(",") )
@@ -182,7 +190,7 @@ module Lita
182
190
  user = response.user.name || response.user.id || robot.name
183
191
  options = parse_options(args[:options]) if args[:options]
184
192
 
185
- # keywoard arguments win over an alias (if someone happens to give both)
193
+ # keyword arguments win over an alias (if someone happens to give both)
186
194
  unless project && job
187
195
  project, job = aliasdb.forward(name)
188
196
  end
@@ -192,13 +200,45 @@ module Lita
192
200
  return
193
201
  end
194
202
 
195
- response.reply resolve(client.run(project,job,options,user))
203
+ execution = client.run(project,job,options,user)
204
+ response.reply resolve(execution)
205
+
206
+ if execution.status == 'running' && args[:report]
207
+ report_back(response, execution, args[:report])
208
+ end
209
+ end
210
+
211
+ def report_back(response, execution, output_limit)
212
+ # remove the output log line limit if value is 'all' or 'full'
213
+ output_limit = nil if /^all$|^full$/i.match(output_limit)
214
+
215
+ # wait the average duration + 1s
216
+ average_duration = execution.job.average_duration.to_i / 1000
217
+ sleep average_duration + 1
218
+
219
+ # check if complete and loop until complete with 10 second check / announce
220
+ while true
221
+ execution = client.execution(execution.id)
222
+ if execution.status == 'running'
223
+ current_duration = Time.now.to_i - execution.start_unixtime.to_i / 1000
224
+ response.reply t(
225
+ "run.still_running",
226
+ id: execution.id,
227
+ current_duration: current_duration,
228
+ average_duration: average_duration
229
+ )
230
+ sleep 10
231
+ else
232
+ response.reply client.output(execution.id, output_limit).pretty_print_output
233
+ return
234
+ end
235
+ end
196
236
  end
197
237
 
198
238
  def resolve(e)
199
239
  case e.status
200
240
  when "running"
201
- t("run.success", id: e.id)
241
+ t("run.success", id: e.id, average_duration: e.job.average_duration.to_f / 1000.0)
202
242
  when "api.error.execution.conflict"
203
243
  t("run.conflict")
204
244
  when "api.error.item.unauthorized"
@@ -208,6 +248,19 @@ module Lita
208
248
  end
209
249
  end
210
250
 
251
+ def output(response)
252
+ id = response.matches[0][0]
253
+ max = response.matches[0][1] if response.matches[0][1]
254
+
255
+ output = client.output(id, max)
256
+
257
+ if output.error_code && output.error_code == 'api.error.item.doesnotexist'
258
+ response.reply t("misc.execution_not_found")
259
+ else
260
+ response.reply output.pretty_print_output
261
+ end
262
+ end
263
+
211
264
  def parse_options(string)
212
265
  options = {}
213
266
  pairs = string.split(/\|/)
@@ -387,6 +440,7 @@ module Lita
387
440
  attr_accessor :url, :token
388
441
 
389
442
  MAX_EXECUTIONS = 10
443
+ MAX_OUTPUT = 10
390
444
 
391
445
  def self.ensure_array(ref)
392
446
  return [ref] if ref.is_a?(Hash)
@@ -402,31 +456,39 @@ module Lita
402
456
  end
403
457
 
404
458
  def get(path,options={})
405
- uri = "#{@url}/#{path}"
459
+ uri = "#{@url}#{path}"
406
460
  # Replace double slashes with a single one, excluding the // after the :
407
461
  uri.gsub!(/([^:])\/\//, '\1/')
408
462
  options[:authtoken] = @token
409
463
 
464
+ request_failed = false
465
+
410
466
  http_response = @http.get(
411
467
  uri,
412
468
  options
413
469
  )
414
470
 
415
- # Trying to avoid nokogiri but not wanting to use ReXML directly,
416
- # hence the xmlsimple gem. ForceArray has usually worked well for
417
- # me, but this XML data seemed to cause it to be inconsistent. So
418
- # the ensure_array method and a little extra code has worked.
419
- hash = ::XmlSimple.xml_in(
420
- http_response.body,
421
- {
422
- "ForceArray" => false,
423
- "GroupTags" => {
424
- "options" => "option"
471
+ hash = {}
472
+ if http_response.body =~ /<.*?>/m
473
+ # Trying to avoid nokogiri but not wanting to use ReXML directly,
474
+ # hence the xmlsimple gem. ForceArray has usually worked well for
475
+ # me, but this XML data seemed to cause it to be inconsistent. So
476
+ # the ensure_array method and a little extra code has worked.
477
+ hash = ::XmlSimple.xml_in(
478
+ http_response.body,
479
+ {
480
+ "ForceArray" => false,
481
+ "GroupTags" => {
482
+ "options" => "option"
483
+ }
425
484
  }
426
- }
427
- )
485
+ )
486
+ else
487
+ @log.error "Request failed: API response not XML"
488
+ request_failed = true
489
+ end
428
490
 
429
- if @debug
491
+ if @debug || request_failed
430
492
  output = options.map{ |k,v| "#{k.to_s}=#{v}" }.join("&")
431
493
  @log.debug "API request: GET #{uri}&#{output}"
432
494
  @log.debug "API response: (HTTP #{http_response.status}) #{http_response.body}"
@@ -437,7 +499,8 @@ module Lita
437
499
  end
438
500
 
439
501
  def info
440
- get('/api/1/system/info')["success"][1]["message"]
502
+ response = get('/api/1/system/info')
503
+ response["success"][1]["message"] if response["success"]
441
504
  end
442
505
 
443
506
  def projects
@@ -456,6 +519,10 @@ module Lita
456
519
  Definition.load(self,job(project,name).id)
457
520
  end
458
521
 
522
+ def execution(id)
523
+ Execution.load(self, id)
524
+ end
525
+
459
526
  def executions(max)
460
527
  max ||= MAX_EXECUTIONS
461
528
  @executions ||= Execution.all(self,max).sort_by{|i| i.id}.reverse[0,max.to_i].reverse
@@ -470,6 +537,11 @@ module Lita
470
537
  job = job(project,name)
471
538
  Job.run(self,job.id,options,user)
472
539
  end
540
+
541
+ def output(id, max)
542
+ max ||= MAX_OUTPUT
543
+ Output.load(self, id, max)
544
+ end
473
545
  end
474
546
 
475
547
  class Project
@@ -529,6 +601,59 @@ module Lita
529
601
  end
530
602
  end
531
603
 
604
+ class Output
605
+ attr_accessor :id, :entries, :completed, :exec_duration, :error_code, :error_message
606
+
607
+ def self.load(client, id, max)
608
+ # @todo Workaround for this: https://github.com/rundeck/rundeck/issues/1207
609
+ max = max.to_i + 2
610
+ response = client.get("/api/5/execution/#{id}/output?lastlines=#{max}")
611
+ if response["output"]
612
+ Output.new(response["output"])
613
+ elsif response["error"][0]
614
+ Output.new(
615
+ "id" => id,
616
+ "error_code" => response["error"][1]["code"],
617
+ "error_message" => response["error"][1]["message"]
618
+ )
619
+ end
620
+ end
621
+
622
+ def initialize(hash)
623
+ @id = hash["id"]
624
+
625
+ if hash["completed"] == "true"
626
+ @completed = true
627
+ elsif hash["completed"] == "false"
628
+ @completed = false
629
+ end
630
+
631
+ @exec_duration = hash["execDuration"]
632
+
633
+ @entries = []
634
+ if hash["entries"] && hash["entries"]["entry"]
635
+ @entries = hash["entries"]["entry"]
636
+ end
637
+
638
+ @error_code = hash["error_code"]
639
+ @error_message = hash["error_message"]
640
+ end
641
+
642
+ def pretty_print_output
643
+ text = ["Execution #{id} output:"]
644
+ entries.each do |entry|
645
+ text.push(" #{entry["time"]} #{entry["content"]}")
646
+ end
647
+
648
+ if @completed
649
+ text.push("Execution #{id} is complete (took #{@exec_duration.to_i / 1000.0}s)")
650
+ else
651
+ text.push("Execution #{id} is not complete (running #{@exec_duration.to_i / 1000.0}s)")
652
+ end
653
+ text.join("\n")
654
+ end
655
+ end
656
+
532
657
  class Job
533
658
  attr_accessor :id, :name, :group, :project, :description,
534
659
  :average_duration, :options
@@ -574,15 +699,15 @@ module Lita
574
699
  @name = hash["name"]
575
700
  @group = hash["group"]
576
701
  @project = hash["project"]
577
- @description = hash["description"]
578
- @average_duration = hash["average_duration"] if hash["average_duration"]
702
+ @description = hash["description"]
703
+ @average_duration = hash["averageDuration"] if hash["averageDuration"]
579
704
  @options = Client.ensure_array(hash["options"]) if hash["options"]
580
705
  end
581
706
  end
582
707
 
583
708
  class Execution
584
- attr_accessor :id, :href, :status, :message, :project, :user, :start,
585
- :end, :job, :description, :argstring, :successful_nodes,
709
+ attr_accessor :id, :href, :status, :message, :project, :user, :start, :start_unixtime,
710
+ :end, :end_unixtime, :job, :description, :argstring, :successful_nodes,
586
711
  :failed_nodes, :aborted_by
587
712
 
588
713
  def self.all(client,max)
@@ -600,6 +725,11 @@ module Lita
600
725
  all
601
726
  end
602
727
 
728
+ def self.load(client, id)
729
+ response = client.get("/api/1/execution/#{id}")
730
+ Execution.new(response["executions"]["execution"]) if response["executions"]["count"].to_i == 1
731
+ end
732
+
603
733
  def initialize(hash)
604
734
  @id = hash["id"]
605
735
  @href = hash["href"]
@@ -607,8 +737,17 @@ module Lita
607
737
  @message = hash["message"]
608
738
  @project = hash["project"]
609
739
  @user = hash["user"]
610
- @start = hash["date-started"]["content"] if hash["date-started"]
611
- @end = hash["date-ended"]["content"] if hash["date-ended"]
740
+
741
+ if hash["date-started"]
742
+ @start_unixtime = hash["date-started"]["unixtime"]
743
+ @start = hash["date-started"]["content"]
744
+ end
745
+
746
+ if hash["date-ended"]
747
+ @end_unixtime = hash["date-ended"]["unixtime"]
748
+ @end = hash["date-ended"]["content"]
749
+ end
750
+
612
751
  @job = Job.new(hash["job"]) if hash["job"]
613
752
  @description = hash["description"]
614
753
  @argstring = hash["argstring"]
@@ -641,7 +780,7 @@ module Lita
641
780
  all
642
781
  end
643
782
 
644
- end
783
+ end
645
784
  end
646
785
  end
647
786
 
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "lita-rundeck"
3
- spec.version = "0.0.2"
3
+ spec.version = "0.0.3"
4
4
  spec.authors = ["Harlan Barnes"]
5
5
  spec.email = ["hbarnes@pobox.com"]
6
6
  spec.description = %q{Lita handler for interacting with Rundeck}
@@ -13,13 +13,15 @@ en:
13
13
  exec_value: "Returns a number of recent executions (default: 10)"
14
14
  running_key: "rundeck running [NUM]"
15
15
  running_value: "Returns currently running executions (default: 10)"
16
- run_key: "rundeck run ( ALIAS_NAME | --project PROJECT_NAME --job JOB_NAME )"
17
- run_value: "Run a project/job either via an alias or explicit names"
16
+ output_key: "rundeck output ID [NUM]"
17
+ output_value: "Returns the last NUM lines (default: 10) of output for execution ID"
18
+ run_key: "rundeck run ( ALIAS_NAME | --project PROJECT_NAME --job JOB_NAME ) [--report all|NUM]"
19
+ run_value: "Run a project/job either via an alias or explicit names; optionally report log back to channel"
18
20
  alias_key: "rundeck alias(es)"
19
21
  alias_value: "List the Rundeck project/job aliases"
20
- alias_register_key: "rundeck alias ALIAS_NAME --project PROJECT_NAME --job JOB_NAME"
22
+ alias_register_key: "rundeck alias register ALIAS_NAME --project PROJECT_NAME --job JOB_NAME"
21
23
  alias_register_value: "Create a new alias for a project / job combination"
22
- alias_forget_key: "rundeck forget ALIAS_NAME"
24
+ alias_forget_key: "rundeck alias forget ALIAS_NAME"
23
25
  alias_forget_value: "Remove an alias"
24
26
  options_key: "rundeck options ( ALIAS_NAME | --project PROJECT_NAME --job JOB_NAME )"
25
27
  options_value: "Describe option details for a project/job either via an alias or explicit names"
@@ -36,7 +38,8 @@ en:
36
38
  token_unauthorized: "API token is unauthorized or lacks runAs permission; check the apitoken.aclpolicy"
37
39
  unauthorized: "You aren't authorized to run jobs"
38
40
  failed: "Something went wrong with the job execution"
39
- success: "Execution %{id} is running"
41
+ success: "Execution %{id} is running. Average job duration is %{average_duration} seconds."
42
+ still_running: "Execution %{id} has been running for %{current_duration}s (%{average_duration}s average)"
40
43
  conflict: "Job is already running and only allows one execution at a time"
41
44
  alias:
42
45
  none: "No aliases have been registered yet"
@@ -49,3 +52,4 @@ en:
49
52
  misc:
50
53
  definition_error: "Something went wrong finding the job definition"
51
54
  job_not_found: "Can't find an alias or project and job"
55
+ execution_not_found: "Can't find execution for this command"
@@ -0,0 +1,23 @@
1
+ <result success='true' apiversion='10'>
2
+ <executions count='1'>
3
+ <execution id='285' href='https://release.bazumedia.com/execution/follow/285' status='succeeded' project='Litatest'>
4
+ <user>admin</user>
5
+ <date-started unixtime='1408028788860'>2014-08-14T15:06:28Z</date-started>
6
+ <date-ended unixtime='1408028808000'>2014-08-14T15:06:48Z</date-ended>
7
+ <job id='3ba7c6c8-3d79-4b02-807f-eda67e321c23' averageDuration='1717'>
8
+ <name>dateoutput</name>
9
+ <group></group>
10
+ <project>Litatest</project>
11
+ <description></description>
12
+ <options>
13
+ <option name='SECONDS' value='30' />
14
+ </options>
15
+ </job>
16
+ <description>Plugin[localexec, nodeStep: true]</description>
17
+ <argstring>-SECONDS 30</argstring>
18
+ <successfulNodes>
19
+ <node name='release.bazumedia.com' />
20
+ </successfulNodes>
21
+ </execution>
22
+ </executions>
23
+ </result>
@@ -0,0 +1,26 @@
1
+ <result success='true' apiversion='10'>
2
+ <output>
3
+ <id>285</id>
4
+ <offset>1545</offset>
5
+ <completed>true</completed>
6
+ <execCompleted>true</execCompleted>
7
+ <hasFailedNodes>false</hasFailedNodes>
8
+ <execState>succeeded</execState>
9
+ <lastModified>1430435800000</lastModified>
10
+ <execDuration>10348</execDuration>
11
+ <percentLoaded>99.61315280464217</percentLoaded>
12
+ <totalSize>1551</totalSize>
13
+ <entries>
14
+ <entry time='23:16:30' absolute_time='2015-04-30T23:16:30Z' level='NORMAL' user='rundeck' command='' stepctx='1' node='rundeck.mycompany.org'>Text of line 1</entry>
15
+ <entry time='23:16:31' absolute_time='2015-04-30T23:16:31Z' level='NORMAL' user='rundeck' command='' stepctx='1' node='rundeck.mycompany.org'>Text of line 2</entry>
16
+ <entry time='23:16:32' absolute_time='2015-04-30T23:16:32Z' level='NORMAL' user='rundeck' command='' stepctx='1' node='rundeck.mycompany.org'>Text of line 3</entry>
17
+ <entry time='23:16:33' absolute_time='2015-04-30T23:16:33Z' level='NORMAL' user='rundeck' command='' stepctx='1' node='rundeck.mycompany.org'>Text of line 4</entry>
18
+ <entry time='23:16:34' absolute_time='2015-04-30T23:16:34Z' level='NORMAL' user='rundeck' command='' stepctx='1' node='rundeck.mycompany.org'>Text of line 5</entry>
19
+ <entry time='23:16:35' absolute_time='2015-04-30T23:16:35Z' level='NORMAL' user='rundeck' command='' stepctx='1' node='rundeck.mycompany.org'>Text of line 6</entry>
20
+ <entry time='23:16:36' absolute_time='2015-04-30T23:16:36Z' level='NORMAL' user='rundeck' command='' stepctx='1' node='rundeck.mycompany.org'>Text of line 7</entry>
21
+ <entry time='23:16:37' absolute_time='2015-04-30T23:16:37Z' level='NORMAL' user='rundeck' command='' stepctx='1' node='rundeck.mycompany.org'>Text of line 8</entry>
22
+ <entry time='23:16:38' absolute_time='2015-04-30T23:16:38Z' level='NORMAL' user='rundeck' command='' stepctx='1' node='rundeck.mycompany.org'>Text of line 9</entry>
23
+ <entry time='23:16:39' absolute_time='2015-04-30T23:16:39Z' level='NORMAL' user='rundeck' command='' stepctx='1' node='rundeck.mycompany.org'>Text of line 10</entry>
24
+ </entries>
25
+ </output>
26
+ </result>
@@ -0,0 +1,15 @@
1
+ <result success='true' apiversion='10'>
2
+ <output>
3
+ <id>6</id>
4
+ <offset>394</offset>
5
+ <completed>true</completed>
6
+ <execCompleted>true</execCompleted>
7
+ <hasFailedNodes>false</hasFailedNodes>
8
+ <execState>succeeded</execState>
9
+ <lastModified>1430436168000</lastModified>
10
+ <execDuration>171</execDuration>
11
+ <percentLoaded>98.5</percentLoaded>
12
+ <totalSize>400</totalSize>
13
+ <entries />
14
+ </output>
15
+ </result>
@@ -0,0 +1,5 @@
1
+ <result error='true' apiversion='10'>
2
+ <error code='api.error.item.doesnotexist'>
3
+ <message>execution does not exist: 9999</message>
4
+ </error>
5
+ </result>
@@ -0,0 +1,21 @@
1
+ <result success='true' apiversion='10'>
2
+ <output>
3
+ <id>285</id>
4
+ <offset>1545</offset>
5
+ <completed>true</completed>
6
+ <execCompleted>true</execCompleted>
7
+ <hasFailedNodes>false</hasFailedNodes>
8
+ <execState>succeeded</execState>
9
+ <lastModified>1430435800000</lastModified>
10
+ <execDuration>10348</execDuration>
11
+ <percentLoaded>99.61315280464217</percentLoaded>
12
+ <totalSize>1551</totalSize>
13
+ <entries>
14
+ <entry time='23:16:35' absolute_time='2015-04-30T23:16:35Z' level='NORMAL' user='rundeck' command='' stepctx='1' node='rundeck.mycompany.org'>Text of line 6</entry>
15
+ <entry time='23:16:36' absolute_time='2015-04-30T23:16:36Z' level='NORMAL' user='rundeck' command='' stepctx='1' node='rundeck.mycompany.org'>Text of line 7</entry>
16
+ <entry time='23:16:37' absolute_time='2015-04-30T23:16:37Z' level='NORMAL' user='rundeck' command='' stepctx='1' node='rundeck.mycompany.org'>Text of line 8</entry>
17
+ <entry time='23:16:38' absolute_time='2015-04-30T23:16:38Z' level='NORMAL' user='rundeck' command='' stepctx='1' node='rundeck.mycompany.org'>Text of line 9</entry>
18
+ <entry time='23:16:39' absolute_time='2015-04-30T23:16:39Z' level='NORMAL' user='rundeck' command='' stepctx='1' node='rundeck.mycompany.org'>Text of line 10</entry>
19
+ </entries>
20
+ </output>
21
+ </result>
@@ -0,0 +1,19 @@
1
+ <result success='true' apiversion='10'>
2
+ <output>
3
+ <id>8</id>
4
+ <offset>1583</offset>
5
+ <completed>false</completed>
6
+ <execCompleted>false</execCompleted>
7
+ <hasFailedNodes>false</hasFailedNodes>
8
+ <execState>running</execState>
9
+ <lastModified>1430873952000</lastModified>
10
+ <execDuration>3750</execDuration>
11
+ <percentLoaded>100.0</percentLoaded>
12
+ <totalSize>1583</totalSize>
13
+ <entries>
14
+ <entry time='23:16:30' absolute_time='2015-04-30T23:16:30Z' level='NORMAL' user='rundeck' command='' stepctx='1' node='rundeck.mycompany.org'>Text of line 1</entry>
15
+ <entry time='23:16:31' absolute_time='2015-04-30T23:16:31Z' level='NORMAL' user='rundeck' command='' stepctx='1' node='rundeck.mycompany.org'>Text of line 2</entry>
16
+ <entry time='23:16:32' absolute_time='2015-04-30T23:16:32Z' level='NORMAL' user='rundeck' command='' stepctx='1' node='rundeck.mycompany.org'>Text of line 3</entry>
17
+ </entries>
18
+ </output>
19
+ </result>
@@ -3,17 +3,17 @@
3
3
  <execution id='285' href='https://rundeck.mycompany.org/execution/follow/285' status='running' project='Litatest'>
4
4
  <user>Shell User</user>
5
5
  <date-started unixtime='1408028788860'>2014-08-14T15:06:28Z</date-started>
6
- <job id='3ba7c6c8-3d79-4b02-807f-eda67e321c23' averageDuration='128717'>
6
+ <job id='3ba7c6c8-3d79-4b02-807f-eda67e321c23' averageDuration='1717'>
7
7
  <name>dateoutput</name>
8
8
  <group></group>
9
9
  <project>Litatest</project>
10
10
  <description></description>
11
11
  <options>
12
- <option name='SECONDS' value='600' />
12
+ <option name='SECONDS' value='30' />
13
13
  </options>
14
14
  </job>
15
15
  <description>Plugin[localexec, nodeStep: true]</description>
16
- <argstring>-SECONDS 600</argstring>
16
+ <argstring>-SECONDS 30</argstring>
17
17
  </execution>
18
18
  </executions>
19
19
  </result>
@@ -3,17 +3,17 @@
3
3
  <execution id='285' href='https://rundeck.mycompany.org/execution/follow/285' status='running' project='Litatest'>
4
4
  <user>Shell User</user>
5
5
  <date-started unixtime='1408028788860'>2014-08-14T15:06:28Z</date-started>
6
- <job id='3ba7c6c8-3d79-4b02-807f-eda67e321c23' averageDuration='128717'>
6
+ <job id='3ba7c6c8-3d79-4b02-807f-eda67e321c23' averageDuration='1717'>
7
7
  <name>dateoutput</name>
8
8
  <group></group>
9
9
  <project>Litatest</project>
10
10
  <description></description>
11
11
  <options>
12
- <option name='SECONDS' value='600' />
12
+ <option name='SECONDS' value='30' />
13
13
  </options>
14
14
  </job>
15
15
  <description>Plugin[localexec, nodeStep: true]</description>
16
- <argstring>-SECONDS 600</argstring>
16
+ <argstring>-SECONDS 30</argstring>
17
17
  </execution>
18
18
  </executions>
19
19
  </result>
@@ -2,6 +2,10 @@ require "spec_helper"
2
2
 
3
3
  describe Lita::Handlers::Rundeck, lita_handler: true do
4
4
 
5
+ let(:rundeck_noxml) do
6
+ "This is not XML and should fail"
7
+ end
8
+
5
9
  let(:rundeck_info) do
6
10
  File.read("spec/files/info.xml")
7
11
  end
@@ -22,6 +26,10 @@ describe Lita::Handlers::Rundeck, lita_handler: true do
22
26
  File.read("spec/files/jobs_empty.xml")
23
27
  end
24
28
 
29
+ let(:rundeck_execution) do
30
+ File.read("spec/files/execution.xml")
31
+ end
32
+
25
33
  let(:rundeck_executions) do
26
34
  File.read("spec/files/executions.xml")
27
35
  end
@@ -58,6 +66,27 @@ describe Lita::Handlers::Rundeck, lita_handler: true do
58
66
  File.read("spec/files/definition.xml")
59
67
  end
60
68
 
69
+ let(:rundeck_output) do
70
+ File.read("spec/files/output.xml")
71
+ end
72
+
73
+ let(:rundeck_output_limit_five) do
74
+ File.read("spec/files/output_limit_five.xml")
75
+ end
76
+
77
+ let(:rundeck_output_empty) do
78
+ File.read("spec/files/output_empty.xml")
79
+ end
80
+
81
+ let(:rundeck_output_exec_noexist) do
82
+ File.read("spec/files/output_exec_noexist.xml")
83
+ end
84
+
85
+
86
+ let(:rundeck_output_notcomplete) do
87
+ File.read("spec/files/output_notcomplete.xml")
88
+ end
89
+
61
90
  it { routes_command("rundeck info").to(:info) }
62
91
  it { routes_command("rundeck projects").to(:projects) }
63
92
  it { routes_command("rundeck jobs").to(:jobs) }
@@ -70,13 +99,18 @@ describe Lita::Handlers::Rundeck, lita_handler: true do
70
99
  it { routes_command("rundeck run aliasfoo --options SECONDS=60").to(:run) }
71
100
  it { routes_command("rundeck run --project Litatest --job dateoutput").to(:run) }
72
101
  it { routes_command("rundeck run --project Litatest --job dateoutput --options SECONDS=60").to(:run) }
102
+ it { routes_command("rundeck run --project Litatest --job dateoutput --options SECONDS=60 --report all").to(:run) }
103
+ it { routes_command("rundeck run --project Litatest --job dateoutput --options SECONDS=60 --report 5").to(:run) }
73
104
  it { routes_command("rundeck options aliasfoo").to(:options) }
74
105
  it { routes_command("rundeck options --project Litatest --job dateoutput").to(:options) }
106
+ it { routes_command("rundeck output 285").to(:output) }
107
+ it { routes_command("rundeck output 285 5").to(:output) }
108
+ it { routes_command("rundeck output 6").to(:output) }
109
+ it { routes_command("rundeck output 7").to(:output) }
75
110
 
76
111
  def grab_request(method, status, body)
77
112
  response = double('Faraday::Response', status: status, body: body)
78
- expect_any_instance_of(Faraday::Connection).to \
79
- receive(method.to_sym).and_return(response)
113
+ expect_any_instance_of(Faraday::Connection).to receive(method.to_sym).and_return(response)
80
114
  end
81
115
 
82
116
  before do
@@ -86,6 +120,13 @@ describe Lita::Handlers::Rundeck, lita_handler: true do
86
120
  end
87
121
 
88
122
  describe "#info" do
123
+ it "returns nothing (but logs a message) if the API response is not XML" do
124
+ grab_request("get", 200, rundeck_noxml)
125
+ send_command("rundeck info")
126
+ # @todo - I don't know rspec well enough to mock up the logger
127
+ expect(replies.last).to be nil
128
+ end
129
+
89
130
  it "replies with the rundeck server information with no users" do
90
131
  grab_request("get", 200, rundeck_info)
91
132
  send_command("rundeck info")
@@ -199,7 +240,7 @@ EOF
199
240
  grab_request("get", 200, rundeck_running)
200
241
  send_command("rundeck running")
201
242
  expect(replies.last).to eq <<-EOF.chomp
202
- 285 running Shell User [Litatest] dateoutput SECONDS:600 start:2014-08-14T15:06:28Z
243
+ 285 running Shell User [Litatest] dateoutput SECONDS:30 start:2014-08-14T15:06:28Z
203
244
  EOF
204
245
  end
205
246
 
@@ -230,7 +271,7 @@ EOF
230
271
  send_command("rundeck alias register aliasfoo --project Litatest --job dateoutput")
231
272
  send_command("rundeck run aliasfoo --options SECONDS=60")
232
273
  expect(replies.last).to eq <<-EOF.chomp
233
- Execution 285 is running
274
+ Execution 285 is running. Average job duration is 1.717 seconds.
234
275
  EOF
235
276
  end
236
277
 
@@ -241,10 +282,115 @@ EOF
241
282
  grab_request("get", 200, rundeck_run)
242
283
  send_command("rundeck run --project Litatest --job dateoutput --options SECONDS=60")
243
284
  expect(replies.last).to eq <<-EOF.chomp
244
- Execution 285 is running
285
+ Execution 285 is running. Average job duration is 1.717 seconds.
286
+ EOF
287
+ end
288
+
289
+ it "submit a fully qualified job and have it report back all the log" do
290
+ allow(Lita::Authorization).to receive(:user_in_group?).and_return(true)
291
+ grab_request("get", 200, rundeck_projects)
292
+ grab_request("get", 200, rundeck_jobs)
293
+ grab_request("get", 200, rundeck_run)
294
+ grab_request("get", 200, rundeck_execution)
295
+ grab_request("get", 200, rundeck_output)
296
+ send_command("rundeck run --project Litatest --job dateoutput --options SECONDS=60 --report all")
297
+ expect(replies.first).to eq <<-EOF.chomp
298
+ Execution 285 is running. Average job duration is 1.717 seconds.
299
+ EOF
300
+ expect(replies.last).to eq <<-EOF.chomp
301
+ Execution 285 output:
302
+ 23:16:30 Text of line 1
303
+ 23:16:31 Text of line 2
304
+ 23:16:32 Text of line 3
305
+ 23:16:33 Text of line 4
306
+ 23:16:34 Text of line 5
307
+ 23:16:35 Text of line 6
308
+ 23:16:36 Text of line 7
309
+ 23:16:37 Text of line 8
310
+ 23:16:38 Text of line 9
311
+ 23:16:39 Text of line 10
312
+ Execution 285 is complete (took 10.348s)
313
+ EOF
314
+ end
315
+
316
+ it "submit a fully qualified job and have it wait at least once, then report back all the log" do
317
+ @time_now = Time.parse("2014-08-14T15:06:33Z")
318
+ expect(Time).to receive(:now).and_return(@time_now)
319
+
320
+ allow(Lita::Authorization).to receive(:user_in_group?).and_return(true)
321
+ grab_request("get", 200, rundeck_projects)
322
+ grab_request("get", 200, rundeck_jobs)
323
+ grab_request("get", 200, rundeck_run)
324
+ grab_request("get", 200, rundeck_running)
325
+ grab_request("get", 200, rundeck_execution)
326
+ grab_request("get", 200, rundeck_output)
327
+ send_command("rundeck run --project Litatest --job dateoutput --options SECONDS=60 --report all")
328
+ expect(replies.first).to eq <<-EOF.chomp
329
+ Execution 285 is running. Average job duration is 1.717 seconds.
330
+ EOF
331
+ expect(replies[1]).to eq <<-EOF.chomp
332
+ Execution 285 has been running for 5s (1s average)
333
+ EOF
334
+ expect(replies.last).to eq <<-EOF.chomp
335
+ Execution 285 output:
336
+ 23:16:30 Text of line 1
337
+ 23:16:31 Text of line 2
338
+ 23:16:32 Text of line 3
339
+ 23:16:33 Text of line 4
340
+ 23:16:34 Text of line 5
341
+ 23:16:35 Text of line 6
342
+ 23:16:36 Text of line 7
343
+ 23:16:37 Text of line 8
344
+ 23:16:38 Text of line 9
345
+ 23:16:39 Text of line 10
346
+ Execution 285 is complete (took 10.348s)
347
+ EOF
348
+ end
349
+
350
+ it "submit a fully qualified job and have it report back a limited log" do
351
+ allow(Lita::Authorization).to receive(:user_in_group?).and_return(true)
352
+ grab_request("get", 200, rundeck_projects)
353
+ grab_request("get", 200, rundeck_jobs)
354
+ grab_request("get", 200, rundeck_run)
355
+ grab_request("get", 200, rundeck_execution)
356
+ grab_request("get", 200, rundeck_output_limit_five)
357
+ send_command("rundeck run --project Litatest --job dateoutput --options SECONDS=60 --report 5")
358
+ expect(replies.first).to eq <<-EOF.chomp
359
+ Execution 285 is running. Average job duration is 1.717 seconds.
360
+ EOF
361
+ expect(replies.last).to eq <<-EOF.chomp
362
+ Execution 285 output:
363
+ 23:16:35 Text of line 6
364
+ 23:16:36 Text of line 7
365
+ 23:16:37 Text of line 8
366
+ 23:16:38 Text of line 9
367
+ 23:16:39 Text of line 10
368
+ Execution 285 is complete (took 10.348s)
245
369
  EOF
246
370
  end
247
371
 
372
+ # it "submit a fully qualified job and have it report back a limited log" do
373
+ # allow(Lita::Authorization).to receive(:user_in_group?).and_return(true)
374
+ # grab_request("get", 200, rundeck_projects)
375
+ # grab_request("get", 200, rundeck_jobs)
376
+ # grab_request("get", 200, rundeck_run)
377
+ # grab_request("get", 200, rundeck_execution)
378
+ # grab_request("get", 200, rundeck_output_limit_five)
379
+ # send_command("rundeck run --project Litatest --job dateoutput --options SECONDS=60 --report 5")
380
+ # expect(replies.first).to eq <<-EOF.chomp
381
+ # Execution 285 is running. Average job duration is 1.717 seconds.
382
+ # EOF
383
+ # expect(replies.last).to eq <<-EOF.chomp
384
+ # Execution 285 output:
385
+ # 23:16:35 Text of line 6
386
+ # 23:16:36 Text of line 7
387
+ # 23:16:37 Text of line 8
388
+ # 23:16:38 Text of line 9
389
+ # 23:16:39 Text of line 10
390
+ # Execution 285 is complete (took 10.348s)
391
+ # EOF
392
+ # end
393
+
248
394
  it "submit a non-existent job" do
249
395
  allow(Lita::Authorization).to receive(:user_in_group?).and_return(true)
250
396
  send_command("rundeck run not-a-real-alias")
@@ -377,6 +523,70 @@ EOF
377
523
  send_command("rundeck options aliasfoo")
378
524
  expect(replies.last).to eq <<-EOF.chomp
379
525
  Can't find an alias or project and job
526
+ EOF
527
+ end
528
+ end
529
+
530
+ describe "#output" do
531
+ it "display output of an existing job with default number of lines" do
532
+ grab_request("get", 200, rundeck_output)
533
+ send_command("rundeck output 5")
534
+ expect(replies.last).to eq <<-EOF.chomp
535
+ Execution 285 output:
536
+ 23:16:30 Text of line 1
537
+ 23:16:31 Text of line 2
538
+ 23:16:32 Text of line 3
539
+ 23:16:33 Text of line 4
540
+ 23:16:34 Text of line 5
541
+ 23:16:35 Text of line 6
542
+ 23:16:36 Text of line 7
543
+ 23:16:37 Text of line 8
544
+ 23:16:38 Text of line 9
545
+ 23:16:39 Text of line 10
546
+ Execution 285 is complete (took 10.348s)
547
+ EOF
548
+ end
549
+
550
+ it "display output of an existing job with custom number of lines (5)" do
551
+ grab_request("get", 200, rundeck_output_limit_five)
552
+ send_command("rundeck output 285 5")
553
+ expect(replies.last).to eq <<-EOF.chomp
554
+ Execution 285 output:
555
+ 23:16:35 Text of line 6
556
+ 23:16:36 Text of line 7
557
+ 23:16:37 Text of line 8
558
+ 23:16:38 Text of line 9
559
+ 23:16:39 Text of line 10
560
+ Execution 285 is complete (took 10.348s)
561
+ EOF
562
+ end
563
+
564
+ it "display output of an existing job that has no output" do
565
+ grab_request("get", 200, rundeck_output_empty)
566
+ send_command("rundeck output 6")
567
+ expect(replies.last).to eq <<-EOF.chomp
568
+ Execution 6 output:
569
+ Execution 6 is complete (took 0.171s)
570
+ EOF
571
+ end
572
+
573
+ it "display output of an existing job that has no output" do
574
+ grab_request("get", 200, rundeck_output_exec_noexist)
575
+ send_command("rundeck output 7")
576
+ expect(replies.last).to eq <<-EOF.chomp
577
+ Can't find execution for this command
578
+ EOF
579
+ end
580
+
581
+ it "display output of an existing job that hasn't completed with default number of lines" do
582
+ grab_request("get", 200, rundeck_output_notcomplete)
583
+ send_command("rundeck output 8")
584
+ expect(replies.last).to eq <<-EOF.chomp
585
+ Execution 8 output:
586
+ 23:16:30 Text of line 1
587
+ 23:16:31 Text of line 2
588
+ 23:16:32 Text of line 3
589
+ Execution 8 is not complete (running 3.75s)
380
590
  EOF
381
591
  end
382
592
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lita-rundeck
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harlan Barnes
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-30 00:00:00.000000000 Z
11
+ date: 2015-05-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lita
@@ -141,11 +141,17 @@ files:
141
141
  - lita-rundeck.gemspec
142
142
  - locales/en.yml
143
143
  - spec/files/definition.xml
144
+ - spec/files/execution.xml
144
145
  - spec/files/executions.xml
145
146
  - spec/files/executions_empty.xml
146
147
  - spec/files/info.xml
147
148
  - spec/files/jobs.xml
148
149
  - spec/files/jobs_empty.xml
150
+ - spec/files/output.xml
151
+ - spec/files/output_empty.xml
152
+ - spec/files/output_exec_noexist.xml
153
+ - spec/files/output_limit_five.xml
154
+ - spec/files/output_notcomplete.xml
149
155
  - spec/files/projects.xml
150
156
  - spec/files/projects_empty.xml
151
157
  - spec/files/run.xml
@@ -183,11 +189,17 @@ specification_version: 4
183
189
  summary: Lita handler for interacting with Rundeck
184
190
  test_files:
185
191
  - spec/files/definition.xml
192
+ - spec/files/execution.xml
186
193
  - spec/files/executions.xml
187
194
  - spec/files/executions_empty.xml
188
195
  - spec/files/info.xml
189
196
  - spec/files/jobs.xml
190
197
  - spec/files/jobs_empty.xml
198
+ - spec/files/output.xml
199
+ - spec/files/output_empty.xml
200
+ - spec/files/output_exec_noexist.xml
201
+ - spec/files/output_limit_five.xml
202
+ - spec/files/output_notcomplete.xml
191
203
  - spec/files/projects.xml
192
204
  - spec/files/projects_empty.xml
193
205
  - spec/files/run.xml