15 changes: 10 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## [v4.1.0](https://github.com/sensu/sensu-puppet/tree/v4.1.0) (2020-01-15)

[Full Changelog](https://github.com/sensu/sensu-puppet/compare/v4.0.0...v4.1.0)

### Added

- Add support for sensuctl 'command' subcommand [\#1195](https://github.com/sensu/sensu-puppet/pull/1195) ([treydock](https://github.com/treydock))

## [v4.0.0](https://github.com/sensu/sensu-puppet/tree/v4.0.0) (2020-01-10)

[Full Changelog](https://github.com/sensu/sensu-puppet/compare/v3.14.0...v4.0.0)
Expand Down Expand Up @@ -72,6 +80,7 @@
- Support Windows 2019 [\#1168](https://github.com/sensu/sensu-puppet/pull/1168) ([treydock](https://github.com/treydock))
- Improve release process [\#1166](https://github.com/sensu/sensu-puppet/pull/1166) ([treydock](https://github.com/treydock))
- \(ci\) Use correct Ruby version 2.5.7 for latest Puppet 6 tests [\#1165](https://github.com/sensu/sensu-puppet/pull/1165) ([ghoneycutt](https://github.com/ghoneycutt))
- Additional bolt tasks [\#1162](https://github.com/sensu/sensu-puppet/pull/1162) ([treydock](https://github.com/treydock))

### Fixed

Expand All @@ -83,7 +92,6 @@

### Added

- Additional bolt tasks [\#1162](https://github.com/sensu/sensu-puppet/pull/1162) ([treydock](https://github.com/treydock))
- Initial work at design document [\#1161](https://github.com/sensu/sensu-puppet/pull/1161) ([treydock](https://github.com/treydock))
- Add bolt tasks [\#1153](https://github.com/sensu/sensu-puppet/pull/1153) ([treydock](https://github.com/treydock))
- Deprecate defining single asset builds [\#1140](https://github.com/sensu/sensu-puppet/pull/1140) ([treydock](https://github.com/treydock))
Expand Down Expand Up @@ -158,10 +166,6 @@

- Add acceptance tests that use puppetserver [\#1123](https://github.com/sensu/sensu-puppet/pull/1123) ([treydock](https://github.com/treydock))

### Fixed

- Fix to support Puppetserver 5 [\#1122](https://github.com/sensu/sensu-puppet/pull/1122) ([treydock](https://github.com/treydock))

## [v3.4.0](https://github.com/sensu/sensu-puppet/tree/v3.4.0) (2019-07-11)

[Full Changelog](https://github.com/sensu/sensu-puppet/compare/v3.3.0...v3.4.0)
Expand All @@ -174,6 +178,7 @@

### Fixed

- Fix to support Puppetserver 5 [\#1122](https://github.com/sensu/sensu-puppet/pull/1122) ([treydock](https://github.com/treydock))
- Update several usage examples to match Sensu Go docs [\#1117](https://github.com/sensu/sensu-puppet/pull/1117) ([treydock](https://github.com/treydock))
- Regenerate backend test cert to include additional SANs [\#1113](https://github.com/sensu/sensu-puppet/pull/1113) ([treydock](https://github.com/treydock))

Expand Down
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ group :development, :unit_tests do
gem 'rubocop', '~> 0.49.0', :require => false
gem 'rubocop-i18n', '~> 1.2.0', :require => false
gem 'rubocop-rspec', '~> 1.16.0', :require => false
if Gem.win_platform? && ENV['PUPPET_GEM_VERSION'] =~ /6.x/
gem 'ffi', '~>1.11.0', :require => false
end
end

group :documentation do
Expand Down
80 changes: 80 additions & 0 deletions REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ _Public Resource types_
* [`sensu_cluster_member`](#sensu_cluster_member): Manages Sensu cluster members
* [`sensu_cluster_role`](#sensu_cluster_role): Manages Sensu cluster roles
* [`sensu_cluster_role_binding`](#sensu_cluster_role_binding): Manages Sensu cluster role bindings
* [`sensu_command`](#sensu_command): Manage sensuctl command resources
* [`sensu_entity`](#sensu_entity): Manages Sensu entities
* [`sensu_etcd_replicator`](#sensu_etcd_replicator): Manages Sensu etcd replicators
* [`sensu_filter`](#sensu_filter): Manages Sensu filters
Expand Down Expand Up @@ -1892,6 +1893,85 @@ namevar

The name of the role binding.

### sensu_command

**Autorequires**:
* `Package[sensu-go-cli]`
* `Service[sensu-backend]`
* `Sensu_configure[puppet]`
* `Sensu_api_validator[sensu]`

#### Examples

##### Add sensuctl command from Bonsai asset

```puppet
sensu_command { 'command-test':
ensure => 'present',
bonsai_name => 'sensu/command-test',
}
```

##### Add command from specific version of a Bonsai asset

```puppet
sensu_command { 'command-test':
ensure => 'present',
bonsai_name => 'sensu/command-test',
bonsai_version => '0.4.0',
}
```

##### Add command from URL

```puppet
sensu_command { 'command-test':
ensure => 'present',
url => 'https://github.com/amdprophet/command-test/releases/download/v0.0.4/command-test_0.0.4_linux_amd64.tar.gz',
sha512 => '67aeba3652def271b1921bc1b4621354ad254c89946ebc8d1e39327f69a902d91f4b0326c9020a4a03e4cfbb718b454b6180f9c39aaff1e60daf6310be66244f'
}
```

#### Properties

The following properties are available in the `sensu_command` type.

##### `ensure`

Valid values: present, absent

The basic property that the resource should be in.

Default value: present

##### `bonsai_version`

Valid values: latest, /[0-9\.]+/

Specific Bonsai asset version to install, or latest

##### `url`

The URL location of the asset.

##### `sha512`

The checksum of the asset

#### Parameters

The following parameters are available in the `sensu_command` type.

##### `name`

namevar

command name

##### `bonsai_name`

Bonsai asset name

### sensu_entity

**Autorequires**:
Expand Down
119 changes: 119 additions & 0 deletions lib/puppet/provider/sensu_command/sensuctl.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'sensuctl'))
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'sensu_api'))

Puppet::Type.type(:sensu_command).provide(:sensuctl, :parent => Puppet::Provider::Sensuctl) do
desc "Provider sensu_command using sensuctl"

mk_resource_methods

def self.instances
commands = []

#TODO: Hack to force JSON format
# Fixed in https://github.com/sensu/sensu-go/pull/3495
current_format = config['format']
sensuctl(['config','set-format','json'])
data = sensuctl_list('command', false, false)
sensuctl(['config','set-format',current_format])

data.each do |d|
command = {}
command[:ensure] = :present
command[:name] = d['alias']
bonsai_namespace = d['asset'].dig('metadata', 'annotations', 'io.sensu.bonsai.namespace')
bonsai_name = d['asset'].dig('metadata', 'annotations', 'io.sensu.bonsai.name')
if bonsai_namespace && bonsai_name
command[:bonsai_name] = "#{bonsai_namespace}/#{bonsai_name}"
end
command[:bonsai_version] = d['asset'].dig('metadata', 'annotations', 'io.sensu.bonsai.version')
command[:url] = d['asset']['url']
command[:sha512] = d['asset']['sha512']
commands << new(command)
end
commands
end

def self.prefetch(resources)
commands = instances
resources.keys.each do |name|
if provider = commands.find { |c| c.name == name }
resources[name].provider = provider
end
end
end

def self.latest_bonsai_version(bonsai_name)
return @latest_version if @latest_version
@latest_version = nil
return nil if bonsai_name.nil?
versions = []
bonsai_asset = Puppet::Provider::SensuAPI.get_bonsai_asset(bonsai_name)
(bonsai_asset['versions'] || []).each do |bonsai_version|
version = bonsai_version['version']
next unless version =~ /^[0-9]/
versions << version
end
versions = versions.sort_by { |v| Gem::Version.new(v) }
@latest_version = versions.last
@latest_version
end

def exists?
@property_hash[:ensure] == :present
end

def initialize(value = {})
super(value)
@property_flush = {}
end

type_properties.each do |prop|
define_method "#{prop}=".to_sym do |value|
@property_flush[prop] = value
end
end

def install
cmd = ['command', 'install', resource[:name]]
if resource[:bonsai_name]
if resource[:bonsai_version] && resource[:bonsai_version].to_s != 'latest'
cmd << "#{resource[:bonsai_name]}:#{resource[:bonsai_version]}"
else
cmd << resource[:bonsai_name]
end
else
cmd << '--url'
cmd << resource[:url]
cmd << '--checksum'
cmd << resource[:sha512]
end
begin
sensuctl(cmd)
rescue Exception => e
raise Puppet::Error, "#{cmd.join(' ')} failed\nError message: #{e.message}"
end
end

def create
install
@property_hash[:ensure] = :present
end

def flush
if !@property_flush.empty?
destroy
install
end
@property_hash = resource.to_hash
end

def destroy
begin
sensuctl_delete('command', resource[:name])
rescue Exception => e
raise Puppet::Error, "sensuctl delete command #{resource[:name]} failed\nError message: #{e.message}"
end
@property_hash.clear
end
end

19 changes: 16 additions & 3 deletions lib/puppet/provider/sensuctl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,18 @@ def sensuctl(*args)
self.class.sensuctl(*args)
end

def self.sensuctl_list(command, namespaces = true)
def self.sensuctl_list(command, namespaces = true, format = true)
args = [command]
args << 'list'
if namespaces
args << '--all-namespaces'
end
args << '--format'
args << 'json'
#TODO: Making format optional is necessary to support sensuctl command list
# Fixed in https://github.com/sensu/sensu-go/pull/3495
if format
args << '--format'
args << 'json'
end
if ! chunk_size.nil?
args << '--chunk-size'
args << chunk_size.to_s
Expand Down Expand Up @@ -196,6 +200,15 @@ def namespaces()
self.class.namespaces()
end

def self.config
output = sensuctl(['config','view'])
data = JSON.parse(output)
return data
rescue Exception => e
Puppet.info("Error executing 'sensuctl config view': #{e}")
return {}
end

def self.valid_json?(json)
return false if json.nil?
JSON.parse(json)
Expand Down
Loading