Skip to content

Commit

Permalink
add cli provider for jenkins_credentials type
Browse files Browse the repository at this point in the history
  • Loading branch information
jhoblitt committed Oct 2, 2015
1 parent 5007275 commit b9e17b7
Show file tree
Hide file tree
Showing 3 changed files with 341 additions and 0 deletions.
1 change: 1 addition & 0 deletions files/puppet_helper.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@ class Actions {
break
case com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey:
info['description'] = cred.description
info['username'] = cred.username
info['private_key'] = cred.privateKey
info['passphrase'] = cred.passphrase.plainText
break
Expand Down
118 changes: 118 additions & 0 deletions lib/puppet/provider/jenkins_credentials/cli.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
require 'puppet/util/warnings'

require 'puppet_x/jenkins/util'
require 'puppet_x/jenkins/provider/cli'

Puppet::Type.type(:jenkins_credentials).provide(:cli, :parent => PuppetX::Jenkins::Provider::Cli) do

mk_resource_methods

def self.instances(catalog = nil)
all = credentials_list_json(catalog)

Puppet.debug("#{sname} instances: #{all.collect {|i| i['id']}}")

all.collect {|info| from_hash(info) }
end

def flush
unless resource.nil?
@property_hash = resource.to_hash
end

case self.ensure
when :present
credentials_update_json
when :absent
credentials_delete_id
else
fail("invalid :ensure value: #{self.ensure}")
end
end

private
def self.copy_key(dst, src, key)
dst[key.to_sym] = src[key.to_s]
end
private_class_method :copy_key

def self.from_hash(info)
# map nil -> :undef
info = PuppetX::Jenkins::Util.undefize(info)

params = {
:name => info['id'],
:ensure => :present,
}

[:impl, :domain, :scope].each {|k| copy_key(params, info, k)}

case info['impl']
when 'UsernamePasswordCredentialsImpl'
[:description, :username, :password].each {|k| copy_key(params, info, k)}
when 'BasicSSHUserPrivateKey'
[:description, :username, :private_key, :passphrase].each {|k| copy_key(params, info, k)}
when 'StringCredentialsImpl'
[:description, :secret].each {|k| copy_key(params, info, k)}
when 'FileCredentialsImpl'
[:description, :file_name, :content].each {|k| copy_key(params, info, k)}
when 'CertificateCredentialsImpl'
[:description, :password, :key_store_implementation].each {|k| copy_key(params, info, k)}

ksi = info['key_store_impl']
params['key_store_impl'] = ksi

case ksi
when 'UploadedKeyStoreSource'
params[:content] = info['content']
when 'FileOnMasterKeyStoreSource'
params[:source] = info['source']
else
Puppet::Util::Warnings.debug_once "#{sname}: unsupported key_store_implementation class #{ksi}"
end
else
Puppet::Util::Warnings.debug_once "#{sname}: unsupported implementation class #{info['impl']}"
end

new(params)
end
private_class_method :from_hash

def to_hash
info = { 'id' => name }

properties = self.class.resource_type.validproperties
properties.reject! {|x| x == :ensure }

properties.each do |prop|
value = @property_hash[prop]
unless value.nil?
info[prop.to_s] = value
end
end

# map :undef -> nil
PuppetX::Jenkins::Util.unundef(info)
end

# array of hashes for multiple "credentials" entries
def self.credentials_list_json(catalog = nil)
raw = clihelper(['credentials_list_json'], :catalog => catalog)

begin
JSON.parse(raw)
rescue JSON::ParserError
fail("unable to parse as JSON: #{raw}")
end
end
private_class_method :credentials_list_json

def credentials_update_json
clihelper(['credentials_update_json'], :stdinjson => to_hash)
end

def credentials_delete_id
# name == "id"
clihelper(['credentials_delete_id', name])
end
end
222 changes: 222 additions & 0 deletions spec/unit/puppet/provider/jenkins_credentials/cli_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
require 'spec_helper'
require 'unit/puppet_x/spec_jenkins_providers'

require 'json'

describe Puppet::Type.type(:jenkins_credentials).provider(:cli) do
let(:credentials_list_json_raw) do
<<-EOS
[
{
"id": "9b07d668-a87e-4877-9407-ae05056e32ac",
"domain": null,
"scope": "GLOBAL",
"impl": "UsernamePasswordCredentialsImpl",
"description": "foo",
"username": "batman",
"password": "password"
},
{
"id": "14dbba6e-fc00-4102-ae97-7a178058f91b",
"domain": null,
"scope": "SYSTEM",
"impl": "BasicSSHUserPrivateKey",
"description": "bar",
"private_key": "-----BEGIN RSA PRIVATE KEY-----",
"passphrase": ""
}
]
EOS
end
let(:credentials) { JSON.parse(credentials_list_json_raw) }

shared_examples "a provider from example hash 1" do
it do
cred = credentials[0]

expect(provider.name).to eq cred['id']
expect(provider.ensure).to eq :present
[
'domain',
'scope',
'impl',
'description',
'username',
'password',
].each do |k|
expect(provider.public_send(k.to_sym)).to eq cred[k].nil? ? :undef : cred[k]
end

[
'private_key',
'passphrase',
].each do |k|
expect(provider.public_send(k.to_sym)).to eq :absent
end
end
end

shared_examples "a provider from example hash 2" do
it do
cred = credentials[1]

expect(provider.name).to eq cred['id']
expect(provider.ensure).to eq :present
[
'domain',
'scope',
'impl',
'description',
'private_key',
'passphrase',
].each do |k|
expect(provider.public_send(k.to_sym)).to eq cred[k].nil? ? :undef : cred[k]
end

[
'username',
'password',
].each do |k|
expect(provider.public_send(k.to_sym)).to eq :absent
end

end
end

include_examples 'confines to cli dependencies'

describe "::instances" do
context "without any params" do
before do
expect(described_class).to receive(:credentials_list_json).
with(nil) { credentials }
end

it "should return the correct number of instances" do
expect(described_class.instances.size).to eq 2
end

context "first instance returned" do
it_behaves_like "a provider from example hash 1" do
let(:provider) do
described_class.instances[0]
end
end
end

context "second instance returned" do
it_behaves_like "a provider from example hash 2" do
let(:provider) do
described_class.instances[1]
end
end
end
end

context "when called with a catalog param" do
it "should pass it on ::credentials_list_json" do
catalog = Puppet::Resource::Catalog.new

expect(described_class).to receive(:credentials_list_json).
with(kind_of(Puppet::Resource::Catalog)) { credentials }

described_class.instances(catalog)
end
end
end # ::instanes

describe '#flush' do
it 'should call credentials_update' do
provider = described_class.new
provider.create

expect(provider).to receive(:credentials_update_json)
provider.flush
end

it 'should call credentials_delete_id' do
provider = described_class.new
provider.destroy

expect(provider).to receive(:credentials_delete_id)
provider.flush
end

it 'should call credentials_delete_id' do
provider = described_class.new

expect(provider).to receive(:credentials_delete_id)
provider.flush
end
end # #flush

#
# private methods
#

describe '::from_hash' do
it_behaves_like "a provider from example hash 1" do
let(:provider) do
described_class.send :from_hash, credentials[0]
end
end

it_behaves_like "a provider from example hash 2" do
let(:provider) do
described_class.send :from_hash, credentials[1]
end
end
end # ::from_hash

describe '::to_hash' do
# not isolated from ::from_hash in the interests of staying DRY
it do
provider = described_class.send :from_hash, credentials[0]
info = provider.send :to_hash

expect(info).to eq credentials[0]
end
end # ::to_hash

describe '::credentials_list_json' do
# not isolated from ::from_hash in the interests of staying DRY
it do
expect(described_class).to receive(:clihelper).with(
['credentials_list_json'],
{:catalog => nil}
) { JSON.pretty_generate(credentials[0]) }

raw = described_class.send :credentials_list_json
expect(raw).to eq credentials[0]
end
end # ::credentials_list_json

describe '#credentials_update_json' do
RSpec::Matchers.define :a_json_doc do |x|
match { |actual| JSON.parse(actual) == x }
end

it do
provider = described_class.send :from_hash, credentials[0]

expect(described_class).to receive(:clihelper).with(
['credentials_update_json'],
{:stdinjson => credentials[0]},
)

provider.send :credentials_update_json
end
end # #credentials_update_json

describe '#credentials_delete_id' do
it do
provider = described_class.send :from_hash, credentials[0]

expect(described_class).to receive(:clihelper).with(
['credentials_delete_id', '9b07d668-a87e-4877-9407-ae05056e32ac']
)

provider.send :credentials_delete_id
end
end # #credentials_delete_id
end

0 comments on commit b9e17b7

Please sign in to comment.