Showing with 239 additions and 3 deletions.
  1. +9 −0 CHANGELOG.md
  2. +26 −2 README.md
  3. +1 −1 metadata.json
  4. +34 −0 spec/acceptance/linux_spec.rb
  5. +10 −0 spec/acceptance/nodesets/ubuntu-14.04.yml
  6. +14 −0 tasks/linux.json
  7. +46 −0 tasks/linux.sh
  8. +14 −0 tasks/windows.json
  9. +85 −0 tasks/windows.ps1
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## Release 0.3.0
### Summary
This release adds the ability to manage services without the puppet-agent being installed on the remote host.

### Added
- Agentless windows service management
- Agentless linux service management
- Linux task service restart

## Release 0.2.0
### Summary
This release uses the PDK convert functionality which in return makes the module PDK compliant. It also includes a roll up of maintenance changes.
Expand Down
28 changes: 26 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@

## Description

This module provides the service task. This task allows you to manage and inspect the state of services, including starting, stopping, enabling, and disabling services.
This module provides services tasks, There are two kinds of tasks. The default task: that uses the puppet agent on the target node to manage and inspect the state of services. The linux task: that manipulates services on a linux derivative without a puppet agent installed on the target node.


## Requirements
This module is compatible with Puppet Enterprise and Puppet Bolt.
Expand All @@ -24,6 +25,8 @@ This module is compatible with Puppet Enterprise and Puppet Bolt.

To run a service task, use the task command, specifying the action and the name of the service.

### Default task

* With PE on the command line, run `puppet task run service action=<ACTION> name=<SERVICE_NAME>`.
* With Bolt on the command line, run `bolt task run service action=<ACTION> name=<SERVICE_NAME>`.

Expand All @@ -32,6 +35,28 @@ For example, to check the status of the Apache httpd service, run:
* With PE, run `puppet task run service action=status name=httpd --nodes neptune`
* With Bolt, run `bolt task run service action=status name=httpd --nodes neptune --modulepath ~/modules`

### Linux task

* With PE on the command line, run `puppet task run service::linux action=<ACTION> name=<SERVICE_NAME>`.
* With Bolt on the command line, run `bolt task run service::linux action=<ACTION> name=<SERVICE_NAME>`.

For example, to check the status of the Apache httpd service, run:

* With PE, run `puppet task run service::linux action=status name=httpd --nodes neptune`
* With Bolt, run `bolt task run service::linux action=status name=httpd --nodes neptune --modulepath ~/modules`

You can also run tasks in the PE console. See PE task documentation for complete information.

### Windows task

* With PE on the command line, run `puppet task run service::windows action=<ACTION> name=<SERVICE_NAME>`.
* With Bolt on the command line, run `bolt task run service::windows action=<ACTION> name=<SERVICE_NAME>`.

For example, to check the status of the lmhosts service, run:

* With PE, run `puppet task run service::windows action=status name=lmhosts --nodes neptune`
* With Bolt, run `bolt task run service::windows action=status name=lmhosts --nodes neptune --modulepath ~/modules`

You can also run tasks in the PE console. See PE task documentation for complete information.

## Reference
Expand All @@ -45,4 +70,3 @@ For a complete list of services that are supported see the Puppet [services](htt
To display help for the service task, run `puppet task show service`

To show help for the task CLI, run `puppet task run --help` or `bolt task run --help`

2 changes: 1 addition & 1 deletion metadata.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "puppetlabs-service",
"version": "0.2.0",
"version": "0.3.0",
"author": "puppet",
"summary": "Tasks that manipulate a service",
"license": "Apache-2.0",
Expand Down
34 changes: 34 additions & 0 deletions spec/acceptance/linux_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# run a test task
require 'spec_helper_acceptance'
# bolt regexes
# expect_multiple_regexes(result: result, regexes: [%r{"status":"(stopped|in_sync)"}, %r{Ran on 1 node}])
# expect_multiple_regexes(result: result, regexes: [%r{"status":"stopped"}, %r{"enabled":"false"}, %r{Ran on 1 node}])

describe 'linux service task', unless: fact_on(default, 'osfamily') == 'windows' do
package_to_use = ''
before(:all) do
if fact_on(default, 'osfamily') == 'RedHat' && fact_on(default, 'operatingsystemrelease') < '6'
run_task(task_name: 'service::linux', params: 'action=stop name=syslog')
end
package_to_use = 'rsyslog'
apply_manifest("package { \"#{package_to_use}\": ensure => present, }")
end
describe 'stop action' do
it "stop #{package_to_use}" do
result = run_task(task_name: 'service::linux', params: "action=stop name=#{package_to_use}")
expect_multiple_regexes(result: result, regexes: [%r{status.*(stop)}, %r{#{task_summary_line}}])
end
end
describe 'start action' do
it "start #{package_to_use}" do
result = run_task(task_name: 'service::linux', params: "action=start name=#{package_to_use}")
expect_multiple_regexes(result: result, regexes: [%r{status.*(start)}, %r{#{task_summary_line}}])
end
end
describe 'restart action' do
it "restart #{package_to_use}" do
result = run_task(task_name: 'service::linux', params: "action=restart name=#{package_to_use}")
expect_multiple_regexes(result: result, regexes: [%r{status.*(restart)}, %r{#{task_summary_line}}])
end
end
end
10 changes: 10 additions & 0 deletions spec/acceptance/nodesets/ubuntu-14.04.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
HOSTS:
ubuntu-14.04:
roles:
- agent
- default
platform: ubuntu-14.04-amd64
box: puppetlabs/ubuntu-14.04-64-nocm
hypervisor: vagrant
CONFIG:
type: foss
14 changes: 14 additions & 0 deletions tasks/linux.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"description": "Manage the state of services (without a puppet agent)",
"input_method": "environment",
"parameters": {
"action": {
"description": "The operation (start, stop) to perform on the service",
"type": "Enum[start, stop, restart]"
},
"name": {
"description": "The name of the service to operate on.",
"type": "String[1]"
}
}
}
46 changes: 46 additions & 0 deletions tasks/linux.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
inux.sh: line 19: local: can only be used in a function
#!/bin/bash

action="$PT_action"
name="$PT_name"
service_managers[0]="systemctl"
service_managers[1]="service"
service_managers[2]="initctl"

# example cli /opt/puppetlabs/puppet/bin/bolt task run service::linux action=stop name=ntp --nodes localhost --modulepath /etc/puppetlabs/code/modules --password puppet --user root

check_command_exists() {
(which "$1") > /dev/null 2>&1
command_exists=$?
return $command_exists
}

for service_manager in "${service_managers[@]}"
do
check_command_exists "$service_manager"
command_exists=$?
if [ $command_exists -eq 0 ]; then
command_line="$service_manager $action $name"
if [ $service_manager == "service" ]; then
command_line="$service_manager $name $action"
fi
output=$($command_line 2>&1)
status_from_command=$?
# set up our status and exit code
if [ $status_from_command -eq 0 ]; then
echo "{ \"status\": \"$name $action\" }"
exit 0
else
# initd is special, starting an already started service is an error
if [[ $service_manager == "service" && "$output" == *"Job is already running"* ]]; then
echo "{ \"status\": \"$name $action\" }"
exit 0
fi
echo "{ \"status\": \"unable to run command '$command_line'\" }"
exit $status_from_command
fi
fi
done

echo "{ \"status\": \"No service managers found\" }"
exit 255
14 changes: 14 additions & 0 deletions tasks/windows.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"description": "Manage the state of Windows services (without a puppet agent)",
"input_method": "powershell",
"parameters": {
"action": {
"description": "The operation (start, stop, restart, status) to perform on the service",
"type": "Enum[start, stop, restart, status]"
},
"name": {
"description": "The short name of the Windows service to operate on.",
"type": "String[1]"
}
}
}
85 changes: 85 additions & 0 deletions tasks/windows.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
[CmdletBinding()]
param(
# NOTE: init.json cannot yet be shared, so must have windows.json / windows.ps1
[Parameter(Mandatory = $true)]
[String]
$Name,

[Parameter(Mandatory = $true)]
[ValidateSet('start', 'stop', 'restart', 'status')]
[String]
$Action
)

$ErrorActionPreference = 'Stop'

function Invoke-ServiceAction($Service, $Action)
{
$inSyncStatus = 'in_sync'
$status = $null

switch ($Action)
{
'start'
{
if ($Service.Status -eq 'Running') { $status = $InSyncStatus }
else { Start-Service $Service }
}
'stop'
{
if ($Service.Status -eq 'Stopped') { $status = $InSyncStatus }
else { Stop-Service $Service }
}
'restart'
{
Restart-Service $Service
$status = 'restarted'
}
# no-op since status always returned
'status' { }
}

# user action
if ($status -eq $null)
{
# https://msdn.microsoft.com/en-us/library/system.serviceprocess.servicecontrollerstatus(v=vs.110).aspx
# ContinuePending, Paused, PausePending, Running, StartPending, Stopped, StopPending
$status = $Service.Status
if ($status -eq 'Running') { $status = 'started' }
}

return $status
}

try
{
$service = Get-Service -Name $Name
$status = Invoke-ServiceAction -Service $service -Action $action

# TODO: could use ConvertTo-Json, but that requires PS3
# if embedding in literal, should make sure Name / Status doesn't need escaping
Write-Host @"
{
"name" : "$($service.Name)",
"action" : "$Action",
"displayName" : "$($service.DisplayName)",
"status" : "$status",
"startType" : "$($service.StartType)"
}
"@
}
catch
{
Write-Host @"
{
"status" : "failure",
"name" : "$Name",
"action" : "$Action",
"_error" : {
"msg" : "Unable to perform '$Action' on '$Name': $($_.Exception.Message)",
"kind": "powershell_error",
"details" : {}
}
}
"@
}