Class: Puppetserver::Ca::Action::List

Inherits:
Object
  • Object
show all
Includes:
Utils
Defined in:
lib/puppetserver/ca/action/list.rb

Constant Summary collapse

SUMMARY =
'List certificates and CSRs'
<<-BANNER
Usage:
  puppetserver ca list [--help]
  puppetserver ca list [--config]
  puppetserver ca list [--all]
  puppetserver ca list --certname NAME[,NAME]

Description:
  List outstanding certificate requests. If --all is specified, signed and
  revoked certificates will be listed as well.

Options:
BANNER
BODY =
JSON.dump({desired_state: 'signed'})

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(logger) ⇒ List

Returns a new instance of List.



34
35
36
# File 'lib/puppetserver/ca/action/list.rb', line 34

def initialize(logger)
  @logger = logger
end

Class Method Details

.parser(parsed = {}) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/puppetserver/ca/action/list.rb', line 38

def self.parser(parsed = {})
  OptionParser.new do |opts|
    opts.banner = BANNER
    opts.on('--config CONF', 'Custom path to Puppet\'s config file') do |conf|
      parsed['config'] = conf
    end
    opts.on('--help', 'Display this command-specific help output') do |help|
      parsed['help'] = true
    end
    opts.on('--all', 'List all certificates') do |a|
      parsed['all'] = true
    end
    opts.on('--certname NAME[,NAME]', Array, 'List the specified cert(s)') do |cert|
      parsed['certname'] = cert
    end
  end
end

Instance Method Details

#format_alt_names(cert) ⇒ Object



142
143
144
145
146
147
148
# File 'lib/puppetserver/ca/action/list.rb', line 142

def format_alt_names(cert)
  # In newer versions of the CA api we return subject_alt_names
  # in addition to dns_alt_names, this field includes DNS alt
  # names but also IP alt names.
  alt_names = cert['subject_alt_names'] || cert['dns_alt_names']
  "alt names: #{alt_names}" unless alt_names.empty?
end

#format_authorization_extensions(cert) ⇒ Object



150
151
152
153
154
155
156
# File 'lib/puppetserver/ca/action/list.rb', line 150

def format_authorization_extensions(cert)
  auth_exts = cert['authorization_extensions']
  return nil if auth_exts.nil? || auth_exts.empty?

  values = auth_exts.map { |ext, value| "#{ext}: #{value}" }.join(', ')
  "authorization extensions: [#{values}]"
end

#format_cert(cert, cert_column_width) ⇒ Object



128
129
130
131
132
133
134
# File 'lib/puppetserver/ca/action/list.rb', line 128

def format_cert(cert, cert_column_width)
  [
    format_cert_and_sha(cert, cert_column_width),
    format_alt_names(cert),
    format_authorization_extensions(cert)
  ].compact.join("\t")
end

#format_cert_and_sha(cert, cert_column_width) ⇒ Object



136
137
138
139
140
# File 'lib/puppetserver/ca/action/list.rb', line 136

def format_cert_and_sha(cert, cert_column_width)
  justified_certname = cert['name'].ljust(cert_column_width + 6)
  sha = cert['fingerprints']['SHA256']
  "    #{justified_certname} (SHA256)  #{sha}"
end

#get_all_certs(settings) ⇒ Object



166
167
168
169
# File 'lib/puppetserver/ca/action/list.rb', line 166

def get_all_certs(settings)
  result = Puppetserver::Ca::CertificateAuthority.new(@logger, settings).get_certificate_statuses
  result ? JSON.parse(result.body) : []
end

#output_certs(certs) ⇒ Object



120
121
122
123
124
125
126
# File 'lib/puppetserver/ca/action/list.rb', line 120

def output_certs(certs)
  cert_column_width = certs.map { |c| c['name'].size }.max

  certs.each do |cert|
    @logger.inform(format_cert(cert, cert_column_width))
  end
end

#output_certs_by_state(requested, signed = [], revoked = [], missing = []) ⇒ Object



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/puppetserver/ca/action/list.rb', line 91

def output_certs_by_state(requested, signed = [], revoked = [], missing = [])
  if revoked.empty? && signed.empty? && requested.empty? && missing.empty?
    @logger.inform "No certificates to list"
    return
  end

  unless requested.empty?
    @logger.inform "Requested Certificates:"
    output_certs(requested)
  end

  unless signed.empty?
    @logger.inform "Signed Certificates:"
    output_certs(signed)
  end

  unless revoked.empty?
    @logger.inform "Revoked Certificates:"
    output_certs(revoked)
  end

  unless missing.empty?
    @logger.inform "Missing Certificates:"
    missing.each do |name|
      @logger.inform "    #{name}"
    end
  end
end

#parse(args) ⇒ Object



171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/puppetserver/ca/action/list.rb', line 171

def parse(args)
  results = {}
  parser = self.class.parser(results)

  errors = CliParsing.parse_with_errors(parser, args)

  errors_were_handled = Errors.handle_with_usage(@logger, errors, parser.help)

  exit_code = errors_were_handled ? 1 : nil

  return results, exit_code
end

#run(input) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/puppetserver/ca/action/list.rb', line 56

def run(input)
  config = input['config']
  certnames = input['certname'] || []
  all = input['all']

  if all && certnames.any?
    Errors.handle_with_usage(@logger, ['Cannot combine use of --all and --certname'])
    return 1
  end

  if config
    errors = FileSystem.validate_file_paths(config)
    return 1 if Errors.handle_with_usage(@logger, errors)
  end

  puppet = Config::Puppet.parse(config, @logger)
  return 1 if Errors.handle_with_usage(@logger, puppet.errors)

  filter_names = certnames.any? \
    ? lambda { |x| certnames.include?(x['name']) }
    : lambda { |x| true }

  all_certs = get_all_certs(puppet.settings).select { |cert| filter_names.call(cert) }
  requested, signed, revoked = separate_certs(all_certs)
  missing = certnames - all_certs.map { |cert| cert['name'] }

  (all || certnames.any?) \
    ? output_certs_by_state(requested, signed, revoked, missing)
    : output_certs_by_state(requested)

  return missing.any? \
    ? 1
    : 0
end

#separate_certs(all_certs) ⇒ Object



158
159
160
161
162
163
164
# File 'lib/puppetserver/ca/action/list.rb', line 158

def separate_certs(all_certs)
  certs = all_certs.group_by { |v| v["state"]}
  requested = certs.fetch("requested", [])
  signed = certs.fetch("signed", [])
  revoked = certs.fetch("revoked", [])
  return requested, signed, revoked
end