a2 0.1.1 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 23a07949036888c04e62fc52f79128f2dcadc32c3774c13677ea127f4492ba71
4
- data.tar.gz: e74e45e471da6be643120a0c38a83ece3dc02f5b9e28d6fdd08651e98d058ead
3
+ metadata.gz: 5ab4e4782cc17d7bdd25d29feda56c81d4dbff2e911f19e9d723f5ecf66801f7
4
+ data.tar.gz: 4993432169fd2305698ee7f1106b0b2a83576eef287ac7065d2543ed38b1cae4
5
5
  SHA512:
6
- metadata.gz: 9f3b5a94eea60a22bf4617725e828569cfa5223482f441982159585438080a63f0d5f4b50ebe500b50c42fcd2c5c4b723afeaa170a69e9e81a069c3b297a1d97
7
- data.tar.gz: 75b703e75a824ccfaa4736679b999653ad3397ccd0c84d050830a5ff6acf4c5d9b8874283b74808c095c6416441dd2d9b23c9a64dc6a9a28d0e4608106ab794c
6
+ metadata.gz: 5cdab720df6fc757d7392598e2ddefed1dfe0883013aca3eb63c95b9b8644ea02de60967b751758c73b312da36d2280ee758a1ae6cbbd92ba9a109ae9d1086ed
7
+ data.tar.gz: e61c4e157f94ff5aca7f69808967cafa12c487bb0978af6726b6772e71d69774791e04c4b04c512ab31857faa15fcca510e645cfc8f3b1d81f6a33b2f2894e3b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- a2 (0.1.1)
4
+ a2 (0.2.0)
5
5
  cmdparse
6
6
  httparty
7
7
 
data/README.md CHANGED
@@ -27,15 +27,11 @@ SSL_NO_VERIFY=true
27
27
  List the available commands:
28
28
 
29
29
  $ a2 --help
30
- Usage: a2 [options] {cfgmgmt | help | iam | node | version}
30
+ Usage: a2 [options] {compliance | help | iam | infra | nodemgmt | version}
31
31
 
32
32
  Available commands:
33
- cfgmgmt Chef Infra config management commands
34
- list-missing-nodes
35
- list-node-status-counts
36
- list-nodes
37
- list-orgs
38
- show-attributes
33
+ compliance Compliance management commands
34
+ export-node-reports
39
35
  help Provide help for individual commands
40
36
  iam Identity access management commands
41
37
  add-membership
@@ -52,7 +48,15 @@ List the available commands:
52
48
  remove-membership
53
49
  update-team
54
50
  update-user
55
- node Node commands
51
+ infra Chef Infra config management commands
52
+ list-missing-nodes
53
+ list-node-runs
54
+ list-node-status-counts
55
+ list-nodes
56
+ list-orgs
57
+ show-attributes
58
+ show-node-run
59
+ nodemgmt Node management commands
56
60
  bulk-delete-by-filter
57
61
  bulk-delete-by-ids
58
62
  delete
data/lib/a2/client.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require_relative 'client/config_mgmt'
2
2
  require_relative 'client/nodes'
3
+ require_relative 'client/reporting'
3
4
  require_relative 'client/teams'
4
5
  require_relative 'client/users'
5
6
 
@@ -7,6 +8,7 @@ module A2
7
8
  class Client
8
9
  include A2::Client::ConfigMgmt
9
10
  include A2::Client::Nodes
11
+ include A2::Client::Reporting
10
12
  include A2::Client::Teams
11
13
  include A2::Client::Users
12
14
 
@@ -45,6 +47,18 @@ module A2
45
47
  JSON.parse(response.body)
46
48
  end
47
49
 
50
+ def download_report(path, json, output_file)
51
+ File.open(output_file, "w") do |file|
52
+ HTTParty.post(File.join(@automate_url, path).to_s, {
53
+ verify: !@ssl_no_verify,
54
+ headers: {"api-token" => @automate_token},
55
+ body: json
56
+ }) do |fragment|
57
+ file.write(fragment)
58
+ end
59
+ end
60
+ end
61
+
48
62
  def delete(path)
49
63
  response = HTTParty.delete(File.join(@automate_url, path).to_s, {
50
64
  verify: !@ssl_no_verify,
@@ -9,6 +9,10 @@ module A2
9
9
  get "/api/v0/cfgmgmt/stats/missing_node_duration_counts#{query_string}"
10
10
  end
11
11
 
12
+ def list_all_node_runs(node_id, query_string = '')
13
+ get "/api/v0/cfgmgmt/nodes/#{node_id}/runs#{query_string}"
14
+ end
15
+
12
16
  def list_all_node_status_counts(query_string = '')
13
17
  get "/api/v0/cfgmgmt/stats/node_counts#{query_string}"
14
18
  end
@@ -20,6 +24,10 @@ module A2
20
24
  def show_attributes(node_id)
21
25
  get "/api/v0/cfgmgmt/nodes/#{node_id}/attribute"
22
26
  end
27
+
28
+ def show_node_run(node_id, run_id, query_string = '')
29
+ get "/api/v0/cfgmgmt/nodes/#{node_id}/runs/#{run_id}#{query_string}"
30
+ end
23
31
  end
24
32
  end
25
33
  end
@@ -0,0 +1,9 @@
1
+ module A2
2
+ class Client
3
+ module Reporting
4
+ def export_node_reports(json, output_file)
5
+ download_report '/api/v0/compliance/reporting/node/export', json, output_file
6
+ end
7
+ end
8
+ end
9
+ end
data/lib/a2/command.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require_relative 'commands/compliance'
1
2
  require_relative 'commands/iam'
2
3
  require_relative 'commands/infra'
3
4
  require_relative 'commands/node_mgmt'
@@ -0,0 +1,14 @@
1
+ require_relative '../subcommands/reporting'
2
+
3
+ module A2
4
+ module Command
5
+ class Compliance < CmdParse::Command
6
+ def initialize
7
+ super('compliance')
8
+ short_desc('Compliance management commands')
9
+ long_desc('Compliance management commands')
10
+ add_command(A2::Subcommand::Reporting::ExportNodeReports.new)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -9,9 +9,11 @@ module A2
9
9
  long_desc('Chef Infra config management commands')
10
10
  add_command(A2::Subcommand::Infra::ListAllCheckedInNodes.new)
11
11
  add_command(A2::Subcommand::Infra::ListMissingNodesCount.new)
12
+ add_command(A2::Subcommand::Infra::ListNodeRuns.new)
12
13
  add_command(A2::Subcommand::Infra::ListNodeStatusCounts.new)
13
14
  add_command(A2::Subcommand::Infra::ListOrganizations.new)
14
15
  add_command(A2::Subcommand::Infra::ShowAttributes.new)
16
+ add_command(A2::Subcommand::Infra::ShowNodeRun.new)
15
17
  end
16
18
  end
17
19
  end
@@ -1,44 +1,44 @@
1
1
  module A2
2
- module Filtered
2
+ class Filtered < CmdParse::Command
3
3
  def initialize(name, opts = {})
4
4
  set_custom_opts!(opts)
5
5
  super(name, opts)
6
- set_filter_optparse_options!(options)
6
+ set_filter_optparse_options!(options, @query_filter)
7
7
  end
8
8
 
9
9
  def set_custom_opts!(opts)
10
10
  @opt ||= {}
11
- @opt[:query_filter] = opts.delete(:query_filter) || false
11
+ @query_filter = opts.delete(:query_filter) || false
12
+ @filter_key = opts.delete(:filter_key) || 'key'
12
13
  end
13
14
 
14
- def set_filter_optparse_options!(options)
15
+ def set_filter_optparse_options!(options, query_filter)
15
16
  options.on('-f', '--filters FILTERS', 'A comma-separated list of filters.') do |filters|
16
17
  @opt[:filters] = filters
17
18
  end
18
- # Only available for POST body filters
19
- options.on('-j', '--json-file FILE', 'Path to a json file containing a filter payload.') do |file|
20
- @opt[:json_file] = file
21
- end unless query_filter?
22
- # Only available for query parameter filters
23
- options.on('-S', '--start START', 'Earliest most recent check-in node information to return. Formatted iso8601 (YYYY-MM-DD\'T\'HH:mm:ssZ)') do |start|
24
- @opt[:start] = start
25
- end if query_filter?
26
- options.on('-E', '--end END', 'Latest most recent check-in node information to return. Formatted iso8601 (YYYY-MM-DD\'T\'HH:mm:ssZ)') do |end_arg|
27
- @opt[:end] = end_arg
28
- end if query_filter?
29
- end
30
-
31
- def query_filter?
32
- @opt[:query_filter]
19
+ if query_filter
20
+ # Only available for query parameter filters
21
+ options.on('-S', '--start-time START', 'Earliest most recent check-in node information to return. Formatted iso8601 (YYYY-MM-DD\'T\'HH:mm:ssZ)') do |start_time|
22
+ @opt[:start] = start_time
23
+ end
24
+ options.on('-E', '--end-time END', 'Latest most recent check-in node information to return. Formatted iso8601 (YYYY-MM-DD\'T\'HH:mm:ssZ)') do |end_time|
25
+ @opt[:end] = end_time
26
+ end
27
+ else
28
+ # Only available for POST body filters
29
+ options.on('-j', '--json-file FILE', 'Path to a json file containing a filter payload.') do |file|
30
+ @opt[:json_file] = file
31
+ end
32
+ end
33
33
  end
34
34
 
35
35
  def parse_filters(filters)
36
36
  parsed_filters = []
37
37
  filters.split(',').each do |f|
38
- k,v = f.split(':')
38
+ k,*v = f.split(':')
39
39
  parsed_filters << {
40
- 'key' => k,
41
- 'values' => [v]
40
+ @filter_key => k,
41
+ 'values' => [v.join(':')]
42
42
  }
43
43
  end
44
44
  parsed_filters
@@ -1,33 +1,26 @@
1
1
  module A2
2
- module Paginated
3
- include A2::Filtered
2
+ class Paginated < Filtered
4
3
  def initialize(name, opts = {})
5
- set_custom_opts!(opts)
4
+ disable_sort_opts = opts.delete(:disable_sort_opts) || false
6
5
  super(name, opts)
7
- @opt = {
8
- order: 'ASC'
9
- }
6
+ @opt[:order] = 'ASC' unless disable_sort_opts
10
7
  options.on('-o', '--order ORDER', 'Return the results in ascending or descending order. Default is "ASC".') do |order|
11
8
  @opt[:order] = order
12
- end
9
+ end unless disable_sort_opts
10
+ options.on('-s', '--sort SORT', 'Sort the results on a specific field.') do |sort|
11
+ @opt[:sort] = sort
12
+ end unless disable_sort_opts
13
13
  options.on('-p', '--page PAGE', Integer, 'Starting page for the results. Default is 0') do |page|
14
14
  @opt[:page] = page
15
15
  end
16
16
  options.on('-P', '--per-page PER_PAGE', Integer, 'The number of results on each page. Default is 100') do |per_page|
17
17
  @opt[:per_page] = per_page
18
18
  end
19
- options.on('-s', '--sort SORT', 'Sort the results on a specific field.') do |sort|
20
- @opt[:sort] = sort
21
- end
22
- set_filter_optparse_options!(options)
23
- end
24
-
25
- def generate_paginated_json_filters
26
- generate_json_filters
19
+ set_filter_optparse_options!(options, @query_filter)
27
20
  end
28
21
 
29
22
  def with_paginated_filter_json(&block)
30
- json = generate_paginated_json_filters
23
+ json = generate_json_filters
31
24
  yield(json)
32
25
  end
33
26
 
data/lib/a2/parser.rb CHANGED
@@ -5,6 +5,7 @@ module A2
5
5
  parser.main_options.version = A2::VERSION
6
6
  parser.add_command(CmdParse::HelpCommand.new)
7
7
  parser.add_command(CmdParse::VersionCommand.new)
8
+ parser.add_command(A2::Command::Compliance.new)
8
9
  parser.add_command(A2::Command::IAM.new)
9
10
  parser.add_command(A2::Command::Infra.new)
10
11
  parser.add_command(A2::Command::NodeMgmt.new)
@@ -1,14 +1,13 @@
1
1
  module A2
2
2
  module Subcommand
3
3
  module Infra
4
- class ListAllCheckedInNodes < CmdParse::Command
5
- include A2::Paginated
4
+ class ListAllCheckedInNodes < Paginated
6
5
  def initialize
7
6
  super('list-nodes', takes_commands: false, query_filter: true)
8
7
  end
9
8
 
10
9
  def execute
11
- with_filter_query do |query_string|
10
+ with_paginated_filter_query do |query_string|
12
11
  puts JSON.pretty_generate(A2::Client.new(command_parser.data).list_all_checked_in_nodes(query_string))
13
12
  end
14
13
  end
@@ -26,8 +25,18 @@ module A2
26
25
  puts JSON.pretty_generate(A2::Client.new(command_parser.data).list_all_missing_nodes_count(@opt[:durations]))
27
26
  end
28
27
  end
29
- class ListNodeStatusCounts < CmdParse::Command
30
- include A2::Filtered
28
+ class ListNodeRuns < Paginated
29
+ def initialize
30
+ super('list-node-runs', takes_commands: false, query_filter: true, disable_sort_opts: true)
31
+ end
32
+
33
+ def execute(node_id)
34
+ with_paginated_filter_query do |query_string|
35
+ puts JSON.pretty_generate(A2::Client.new(command_parser.data).list_all_node_runs(node_id, query_string))
36
+ end
37
+ end
38
+ end
39
+ class ListNodeStatusCounts < Filtered
31
40
  def initialize
32
41
  super('list-node-status-counts', takes_commands: false, query_filter: true)
33
42
  end
@@ -56,6 +65,22 @@ module A2
56
65
  puts JSON.pretty_generate(A2::Client.new(command_parser.data).show_attributes(node_id))
57
66
  end
58
67
  end
68
+ class ShowNodeRun < CmdParse::Command
69
+ def initialize
70
+ super('show-node-run', takes_commands: false)
71
+ @opt = {}
72
+ options.on('-E', '--end-time END', "End time on the node's run. Formatted iso8601 (YYYY-MM-DD\'T\'HH:mm:ssZ)") do |end_time|
73
+ @opt[:end_time] = end_time
74
+ end
75
+ end
76
+
77
+ def execute(node_id, run_id)
78
+ query_string = ''
79
+ query_string = "?end_time=#{@opt[:end_time]}" if @opt[:end_time]
80
+
81
+ puts JSON.pretty_generate(A2::Client.new(command_parser.data).show_node_run(node_id, run_id, query_string))
82
+ end
83
+ end
59
84
  end
60
85
  end
61
86
  end
@@ -10,8 +10,7 @@ module A2
10
10
  puts JSON.pretty_generate(A2::Client.new(command_parser.data).get_managed_node(id))
11
11
  end
12
12
  end
13
- class Search < CmdParse::Command
14
- include A2::Paginated
13
+ class Search < Paginated
15
14
 
16
15
  def initialize
17
16
  super('search', takes_commands: false)
@@ -25,7 +24,6 @@ module A2
25
24
  end
26
25
  class Delete < CmdParse::Command
27
26
  include A2::Approved
28
-
29
27
  def initialize
30
28
  super('delete', takes_commands: false)
31
29
  end
@@ -38,7 +36,6 @@ module A2
38
36
  end
39
37
  class BulkDeleteById < CmdParse::Command
40
38
  include A2::Approved
41
-
42
39
  def initialize
43
40
  super('bulk-delete-by-ids', takes_commands: false)
44
41
  end
@@ -49,10 +46,8 @@ module A2
49
46
  end
50
47
  end
51
48
  end
52
- class BulkDeleteByFilter < CmdParse::Command
49
+ class BulkDeleteByFilter < Paginated
53
50
  include A2::Approved
54
- include A2::Paginated
55
-
56
51
  def initialize
57
52
  super('bulk-delete-by-filter', takes_commands: false)
58
53
  end
@@ -0,0 +1,30 @@
1
+ module A2
2
+ module Subcommand
3
+ module Reporting
4
+ class ExportNodeReports < Paginated
5
+ def initialize
6
+ super('export-node-reports', takes_commands: false, filter_key: 'type')
7
+ @opt[:type] = 'csv'
8
+ options.on('-n', '--name NAME', 'Name of the profile (as defined in inspec.yml).') do |name|
9
+ @opt[:name] = name
10
+ end
11
+ options.on('-O', '--owner OWNER', 'Automate user associated with the profile.') do |owner|
12
+ @opt[:owner] = owner
13
+ end
14
+ options.on('-o', '--output OUTPUT_TYPE', 'Desired report data format (either "csv" or "json"). Default value is "csv".') do |output_type|
15
+ @opt[:type] = output_type
16
+ end
17
+ end
18
+
19
+ def execute(filename = nil, output_type = 'csv')
20
+ # Workaround for bug: https://github.com/chef/automate/issues/4926
21
+ @opt[:order] = @opt[:order].downcase.eql?('asc') ? 0 : 1
22
+ with_paginated_filter_json do |json|
23
+ filename ||= "report-#{Time.now.strftime('%Y%m%d%H%M%S')}.#{@opt[:type]}"
24
+ response = A2::Client.new(command_parser.data).export_node_reports(json, filename)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -48,7 +48,6 @@ module A2
48
48
  end
49
49
  class Delete < CmdParse::Command
50
50
  include A2::Approved
51
-
52
51
  def initialize
53
52
  super('delete-team', takes_commands: false)
54
53
  end
data/lib/a2/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module A2
2
- VERSION = '0.1.1'
2
+ VERSION = '0.2.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: a2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - gscho
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-24 00:00:00.000000000 Z
11
+ date: 2021-04-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -106,9 +106,11 @@ files:
106
106
  - lib/a2/client.rb
107
107
  - lib/a2/client/config_mgmt.rb
108
108
  - lib/a2/client/nodes.rb
109
+ - lib/a2/client/reporting.rb
109
110
  - lib/a2/client/teams.rb
110
111
  - lib/a2/client/users.rb
111
112
  - lib/a2/command.rb
113
+ - lib/a2/commands/compliance.rb
112
114
  - lib/a2/commands/iam.rb
113
115
  - lib/a2/commands/infra.rb
114
116
  - lib/a2/commands/node_mgmt.rb
@@ -118,6 +120,7 @@ files:
118
120
  - lib/a2/parser.rb
119
121
  - lib/a2/subcommands/infra.rb
120
122
  - lib/a2/subcommands/node_mgmt.rb
123
+ - lib/a2/subcommands/reporting.rb
121
124
  - lib/a2/subcommands/team.rb
122
125
  - lib/a2/subcommands/user.rb
123
126
  - lib/a2/version.rb