Skip to content

Commit 34603a6

Browse files
committed
(FM-8079) Resource API and Transports Hands-on-Lab
1 parent 775cd7a commit 34603a6

17 files changed

+920
-0
lines changed

docs/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Resource API hands-on lab
2+
3+
This lab will walk you through the basic steps of creating a native integration with puppet. After this you will have a fully functioning module to manage Philips HUE lights and have seen all the bits fall into place.
4+
5+
These labs are intended for new and experienced developers alike. Please post feedback and suggestions for improvement in the [issues section](https://github.com/puppetlabs/puppet-resource_api/issues).
6+
7+
Start with [installing the Puppet Development Kit](./hands-on-lab/01-installing-prereqs.md)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Install the Puppet Development Kit and other tools
2+
3+
To start out, install the Puppet Development Kit (PDK), which will provide all necessary tools and libraries to build and test modules. Additionally we recommend an emulator for the target device of this lab, a code editor with good ruby and puppet support, and GIT, a version control system to keep track of our progress.
4+
5+
1. Choose your platform from https://puppet.com/download-puppet-development-kit; download and install the package
6+
7+
2. If you do not have a Philips HUE hub available, you can download the [Hue-Emulator](https://github.com/SteveyO/Hue-Emulator/raw/master/HueEmulator-v0.8.jar). You will need to have Java installed to run this.
8+
9+
3. To edit code, we recommend the cross-platform editor [VSCode](https://code.visualstudio.com/download), with the [Ruby](https://marketplace.visualstudio.com/items?itemName=rebornix.Ruby) and [Puppet](https://marketplace.visualstudio.com/items?itemName=jpogran.puppet-vscode) extensions. There are lots of other extensions that can help you with your development workflow.
10+
11+
4. Git is a version control system that helps you keep track of changes and collaborate with others. In the course of the hands-on lab, we will show some integrations with cloud services that can help you. If you never used git before, skip this and all related steps for now.
12+
13+
14+
## Next up
15+
16+
Having installed all of this, let's [light up a few](./02-connecting-to-the-lightbulbs.md).
42.3 KB
Loading
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Connecting to the Lightbulbs
2+
3+
While there are no technical restrictions on the kinds of remote devices or APIs you can connect to with transports, for the purpose of this workshop we are connecting to a Philips HUE hub and make some colourful wireless lightbulbs light up. If you (understandably) do not have physical devices available, you can get going with the Hue Emulator.
4+
5+
## Hue Emulator
6+
7+
Download the [HueEmulator-v0.8.jar](https://github.com/SteveyO/Hue-Emulator/blob/master/HueEmulator-v0.8.jar) from [SteveyO/Hue-Emulator](https://github.com/SteveyO/Hue-Emulator).
8+
9+
To run this emulator, you will need to have a Java Runtime installed. Once you have java installed, use `java -jar` with the emulator's filename to run it:
10+
11+
```
12+
david@davids:~$ java -jar ~/Downloads/HueEmulator-v0.8.jar
13+
```
14+
15+
It will not produce any output on the command line, but it will pop up a window with a hub and a few predefined lights:
16+
17+
![](./02-connecting-to-the-lightbulbs-emulator.png)
18+
19+
All you need now is to input a port (the default 8000 is usually fine) and press "Start" to activate the built-in server.
20+
21+
## Connecting to your hub
22+
23+
To connect to an actual hub, you will need be able to access the Hub on your network and get an API key. Follow the [Philips Developer docs](http://www.developers.meethue.com/documentation/getting-started) (registration required) for that.
24+
25+
26+
## Next up
27+
28+
Once you have some lights up, head on to [create a new module](./03-creating-a-new-module.md).
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Create a new module
2+
3+
Depending on your preferences, you can use the VSCode/PDK integration or run the PDK from the command line in a terminal of your choice.
4+
5+
## VSCode
6+
7+
Hit up the Command Palette (⇧⌘P on the Mac or Ctrl+Shift+P on Windows and Linux) and search for the `Puppet: PDK New Module` task:
8+
9+
![](./03-creating-a-new-module_vscode.png)
10+
11+
Press Enter (↩) to execute this and follow the on-screen prompts.
12+
13+
The module will open in a new VSCode window.
14+
15+
## Command Line
16+
17+
In your regular workspace (for example your home directory) run
18+
19+
```
20+
pdk new module hue_workshop --skip-interview
21+
```
22+
23+
This will create a new module `hue_workshop` in a directory of the same name, using all defaults. Output should look like the following:
24+
25+
```
26+
david@davids:~/tmp$ pdk new module hue_workshop --skip-interview
27+
pdk (INFO): Creating new module: hue_workshop
28+
pdk (INFO): Module 'hue_workshop' generated at path '/home/david/tmp/hue_workshop', from template 'file:///opt/puppetlabs/pdk/share/cache/pdk-templates.git'.
29+
pdk (INFO): In your module directory, add classes with the 'pdk new class' command.
30+
david@davids:~/tmp$ ls hue_workshop/
31+
appveyor.yml data files Gemfile.lock manifests Rakefile spec templates
32+
CHANGELOG.md examples Gemfile hiera.yaml metadata.json README.md tasks
33+
david@davids:~/tmp$
34+
```
35+
36+
To read more about the different options when creating new modules see [the PDK docs](https://puppet.com/docs/pdk/1.x/pdk_creating_modules.html).
37+
38+
Open the new directory in VSCode, or your coding editor of choice:
39+
40+
```
41+
code -a hue_workshop
42+
```
43+
44+
For this workshop, we'll active a few future defaults to make our lives easier down the line. Directly in the `hue_workshop` directory, create a file called `.sync.yml` and paste the following snippet:
45+
46+
```
47+
# .sync.yml
48+
---
49+
Gemfile:
50+
optional:
51+
':development':
52+
- gem: 'puppet-resource_api'
53+
- gem: 'faraday'
54+
- gem: 'rspec-json_expectations'
55+
spec/spec_helper.rb:
56+
mock_with: ':rspec'
57+
```
58+
59+
Then run `pdk update` in the module's directory to deploy the changes into the module:
60+
61+
```
62+
david@davids:~/tmp/hue_workshop$ pdk update
63+
pdk (INFO): Updating david-hue_workshop using the default template, from 1.10.0 to 1.10.0
64+
65+
----------Files to be modified----------
66+
Gemfile
67+
spec/spec_helper.rb
68+
69+
----------------------------------------
70+
71+
You can find a report of differences in update_report.txt.
72+
73+
Do you want to continue and make these changes to your module? Yes
74+
75+
------------Update completed------------
76+
77+
2 files modified.
78+
79+
david@davids:~/tmp/hue_workshop$
80+
```
81+
82+
83+
## Next up
84+
85+
Once you have the module ready, head on to [add a transport](./04-adding-a-new-transport.md).
21.7 KB
Loading
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Add a new transport
2+
3+
[Eventually](https://github.com/puppetlabs/pdk/pull/666) there will be a `pdk new transport`, for now you'll need to copy in a few files for this workshop.
4+
5+
Copy the files from [this directory](./04-adding-a-new-transport/) into your new module:
6+
7+
* .sync.yml
8+
* lib/puppet/transport/hue.rb
9+
* lib/puppet/transport/schema/hue.rb
10+
* lib/puppet/util/network_device/hue/device.rb
11+
* spec/unit/puppet/transport/hue_spec.rb
12+
* spec/unit/puppet/transport/schema/hue_spec.rb
13+
14+
Afterwards run `pdk update --force` to enable a few future defaults that are required for these templates:
15+
16+
```
17+
david@davids:~/tmp/hue$ pdk update --force
18+
pdk (INFO): Updating david-hue using the default template, from master@c43fc26 to master@c43fc26
19+
20+
----------Files to be modified----------
21+
Gemfile
22+
spec/spec_helper.rb
23+
24+
----------------------------------------
25+
26+
You can find a report of differences in update_report.txt.
27+
28+
[✔] Resolving default Gemfile dependencies.
29+
30+
------------Update completed------------
31+
32+
2 files modified.
33+
34+
david@davids:~/tmp/hue$
35+
```
36+
37+
## Checkpoint
38+
39+
To make sure that everything went well with creating the module and copying in the files you can run `pdk validate --parallel` and `pdk test unit`:
40+
41+
```
42+
david@davids:~/tmp/hue$ pdk validate --parallel
43+
pdk (INFO): Running all available validators...
44+
pdk (INFO): Using Ruby 2.5.5
45+
pdk (INFO): Using Puppet 6.4.2
46+
┌ [✔] Validating module using 5 threads ┌
47+
├──[✔] Checking metadata syntax (metadat├──son tasks/*.json).
48+
├──[✔] Checking task names (tasks/**/*).├──
49+
└──[✔] Checking YAML syntax (["**/*.yaml├──"*.yaml", "**/*.yml", "*.yml"]).
50+
└──[/] Checking module metadata style (metadata.json).
51+
└──[✔] Checking module metadata style (metadata.json).
52+
info: puppet-syntax: ./: Target does not contain any files to validate (**/*.pp).
53+
info: task-metadata-lint: ./: Target does not contain any files to validate (tasks/*.json).
54+
info: puppet-lint: ./: Target does not contain any files to validate (**/*.pp).
55+
david@davids:~/tmp/hue$ pdk test unit
56+
pdk (INFO): Using Ruby 2.5.5
57+
pdk (INFO): Using Puppet 6.4.2
58+
[✔] Preparing to run the unit tests.
59+
[✔] Running unit tests in parallel.
60+
Run options: exclude {:bolt=>true}
61+
Evaluated 6 tests in 2.405066937 seconds: 0 failures, 0 pending.
62+
david@davids:~/tmp/hue$
63+
```
64+
65+
If you're working with a version control system, this would also be a good point to make the first commit to store away all the boilerplate code and later revisit the changes you made. Here I'm showing how to initialise a local git repository and storing all files in an initial commit:
66+
67+
```
68+
david@davids:~/tmp/hue$ git init
69+
Initialized empty Git repository in ~/tmp/hue/.git/
70+
david@davids:~/tmp/hue$ git add -A
71+
david@davids:~/tmp/hue$ git commit -m 'initial commit'
72+
[master (root-commit) 67951dd] initial commit
73+
26 files changed, 887 insertions(+)
74+
create mode 100644 .fixtures.yml
75+
create mode 100644 .gitattributes
76+
create mode 100644 .gitignore
77+
create mode 100644 .gitlab-ci.yml
78+
create mode 100644 .pdkignore
79+
create mode 100644 .puppet-lint.rc
80+
create mode 100644 .rspec
81+
create mode 100644 .rubocop.yml
82+
create mode 100644 .sync.yml
83+
create mode 100644 .travis.yml
84+
create mode 100644 .yardopts
85+
create mode 100644 CHANGELOG.md
86+
create mode 100644 Gemfile
87+
create mode 100644 README.md
88+
create mode 100644 Rakefile
89+
create mode 100644 appveyor.yml
90+
create mode 100644 data/common.yaml
91+
create mode 100644 hiera.yaml
92+
create mode 100644 lib/puppet/transport/hue.rb
93+
create mode 100644 lib/puppet/transport/schema/hue.rb
94+
create mode 100644 lib/puppet/util/network_device/hue/device.rb
95+
create mode 100644 metadata.json
96+
create mode 100644 spec/default_facts.yml
97+
create mode 100644 spec/spec_helper.rb
98+
create mode 100644 spec/unit/puppet/transport/hue_spec.rb
99+
create mode 100644 spec/unit/puppet/transport/schema/hue_spec.rb
100+
david@davids:~/tmp/hue$
101+
```
102+
103+
## Next up
104+
105+
Once you have everything ready, head on to [implement the transport](./05-implementing-the-transport.md).
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# use future defaults
2+
---
3+
Gemfile:
4+
optional:
5+
':development':
6+
- gem: 'puppet-resource_api'
7+
spec/spec_helper.rb:
8+
mock_with: ':rspec'
9+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
module Puppet::Transport
2+
# The main connection class to a Hue endpoint
3+
class Hue
4+
# Initialise this transport with a set of credentials
5+
def initialize(context, connection_info)
6+
# because `password` is marked sensitive, we can log it here and it will be masked
7+
context.debug("Connecting to #{connection_info[:user]}:#{connection_info[:password]}@#{connection_info[:host]}:#{connection_info[:port]}")
8+
# store the credentials for later use
9+
# alternatively, connect right here
10+
@connection_info = connection_info
11+
end
12+
13+
# Verifies that the stored credentials are valid, and that we can talk to the target
14+
def verify(context)
15+
context.debug("Checking connection to #{@connection_info[:host]}:#{@connection_info[:port]}")
16+
# in a real world implementation, the password would be checked by connecting
17+
# to the target device or checking that an existing connection is still alive
18+
raise 'authentication error' if @connection_info[:password].unwrap == 'invalid'
19+
end
20+
21+
# Retrieve facts from the target and return in a hash
22+
def facts(context)
23+
context.debug('Retrieving facts')
24+
{
25+
operatingsystem: 'example',
26+
operatingsystemrelease: '1.2.3.4',
27+
}
28+
end
29+
30+
# Close the connection and release all resources
31+
def close(context)
32+
context.debug('Closing connection')
33+
@connection_info = nil
34+
end
35+
end
36+
end
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
require 'puppet/resource_api'
2+
3+
Puppet::ResourceApi.register_transport(
4+
name: 'hue',
5+
desc: <<-DESC,
6+
This transport provides Puppet with the capability to connect to hue targets.
7+
DESC
8+
features: [],
9+
connection_info: {
10+
host: {
11+
type: 'String',
12+
desc: 'The hostname or IP address to connect to for this target.',
13+
},
14+
port: {
15+
type: 'Optional[Integer]',
16+
desc: 'The port to connect to. Defaults to ...',
17+
},
18+
user: {
19+
type: 'String',
20+
desc: 'The name of the user to authenticate as.',
21+
},
22+
password: {
23+
type: 'String',
24+
desc: 'The password for the user.',
25+
sensitive: true,
26+
},
27+
},
28+
)

0 commit comments

Comments
 (0)