Class: Puppetserver::Ca::SignAction

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

Constant Summary collapse

SUMMARY =
'Sign a given certificate'
<<-BANNER
Usage:
  puppetserver ca sign [--help|--version]
  puppetserver ca sign [--config] --certname CERTNAME[,CERTNAME]
  puppetserver ca sign  --all

Description:
Given a comma-separated list of valid certnames, instructs the CA to sign each cert.

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

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(logger) ⇒ SignAction

Returns a new instance of SignAction.



51
52
53
# File 'lib/puppetserver/ca/sign_action.rb', line 51

def initialize(logger)
  @logger = logger
end

Class Method Details

.parser(parsed = {}) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/puppetserver/ca/sign_action.rb', line 30

def self.parser(parsed = {})
  OptionParser.new do |opts|
    opts.banner = BANNER
    opts.on('--certname x,y,z', Array, 'the name(s) of the cert(s) to be signed') do |cert|
      parsed['certname'] = cert
    end
    opts.on('--config PUPPET.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('--version', 'Output the version') do |v|
      parsed['version'] = true
    end
    opts.on('--all', 'Operate on all certnames') do |a|
      parsed['all'] = true
    end
  end
end

Instance Method Details

#check_flag_usage(results) ⇒ Object



163
164
165
166
167
168
169
170
171
172
# File 'lib/puppetserver/ca/sign_action.rb', line 163

def check_flag_usage(results)
  if results['certname'] && results['all']
    '--all and --certname cannot be used together'
  elsif !results['certname'] && !results['all']
    'No arguments given'
  elsif results['certname'] && results['certname'].include?('--all')
    'Cannot use --all with --certname. If you actually have a certificate request ' +
                    'for a certifcate named --all, you need to use the HTTP API.'
  end
end

#get_all_certs(settings) ⇒ Object



111
112
113
114
115
116
117
118
119
120
# File 'lib/puppetserver/ca/sign_action.rb', line 111

def get_all_certs(settings)
  result = get_certificate_statuses(settings)

  unless result.code == 200
      @logger.err 'Error:'
      @logger.err "    #{result.inspect}"
      return nil
  end
  return result
end

#get_all_pending_certs(settings) ⇒ Object



134
135
136
137
138
139
# File 'lib/puppetserver/ca/sign_action.rb', line 134

def get_all_pending_certs(settings)
  result = get_all_certs(settings)
  if result
    select_pending_certs(result.body)
  end
end

#get_certificate_statuses(settings) ⇒ Object



85
86
87
88
89
90
91
92
93
94
# File 'lib/puppetserver/ca/sign_action.rb', line 85

def get_certificate_statuses(settings)
  client = http_client(settings)
  url = client.make_ca_url(settings[:ca_server],
                           settings[:ca_port],
                           'certificate_statuses',
                           'any_key')
  client.with_connection(url) do |connection|
    connection.get(url)
  end
end

#http_client(settings) ⇒ Object



79
80
81
82
83
# File 'lib/puppetserver/ca/sign_action.rb', line 79

def http_client(settings)
  @client ||= HttpClient.new(settings[:localcacert],
                             settings[:certificate_revocation],
                             settings[:hostcrl])
end

#parse(args) ⇒ Object



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/puppetserver/ca/sign_action.rb', line 174

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

  errors = Utils.parse_with_errors(parser, args)

  if check_flag_usage(results)
    errors << check_flag_usage(results)
  end

  errors_were_handled = Utils.handle_errors(@logger, errors, parser.help)

  exit_code = errors_were_handled ? 1 : nil

  return results, exit_code
end

#run(input) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/puppetserver/ca/sign_action.rb', line 55

def run(input)
  config = input['config']

  if config
    errors = FileUtilities.validate_file_paths(config)
    return 1 if Utils.handle_errors(@logger, errors)
  end

  puppet = PuppetConfig.parse(config)
  return 1 if Utils.handle_errors(@logger, puppet.errors)

  if input['all']
    requested_certnames = get_all_pending_certs(puppet.settings)
    if requested_certnames.nil?
      return 1
    end
  else
    requested_certnames = input['certname']
  end

  success = sign_requested_certs(requested_certnames, puppet.settings)
  return success ? 0 : 1
end

#select_pending_certs(get_result) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
# File 'lib/puppetserver/ca/sign_action.rb', line 122

def select_pending_certs(get_result)
  requested_certnames = JSON.parse(get_result).select{|e| e["state"] == "requested"}.map{|e| e["name"]}

  if requested_certnames.empty?
    @logger.err 'Error:'
    @logger.err "    No waiting certificate requests to sign"
    return nil
  end

  return requested_certnames
end

#sign_certs(certnames, settings) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/puppetserver/ca/sign_action.rb', line 96

def sign_certs(certnames,settings)
  results = {}
  client = http_client(settings)
  url = client.make_ca_url(settings[:ca_server],
                           settings[:ca_port],
                           'certificate_status')
  client.with_connection(url) do |connection|
    certnames.each do |certname|
      url.resource_name = certname
      results[certname] = connection.put(BODY, url)
    end
  end
  return results
end

#sign_requested_certs(certnames, settings) ⇒ Object



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/puppetserver/ca/sign_action.rb', line 141

def sign_requested_certs(certnames,settings)
  success = true
  results = sign_certs(certnames, settings)
  results.each do |certname, result|
    case result.code
    when '204'
      @logger.inform "Signed certificate for #{certname}"
    when '404'
      @logger.err 'Error:'
      @logger.err "    Could not find certificate for #{certname}"
      success = false
    else
      @logger.err 'Error:'
      @logger.err "    When download requested for #{result.inspect}"
      @logger.err "    code: #{result.code}"
      @logger.err "    body: #{result.body.to_s}" if result.body
      success = false
    end
  end
  return success
end