opscode-pushy-client 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +88 -0
- data/Gemfile +20 -0
- data/Gemfile.lock +242 -0
- data/LICENSE +201 -0
- data/README.md +43 -0
- data/RELEASE_PROCESS.md +105 -0
- data/Rakefile +42 -0
- data/bin/print_execution_environment +18 -0
- data/bin/push-apply +47 -0
- data/bin/pushy-client +8 -0
- data/bin/pushy-service-manager +19 -0
- data/jenkins/jenkins_run_tests.sh +9 -0
- data/keys/client_private.pem +27 -0
- data/keys/server_public.pem +9 -0
- data/lib/pushy_client.rb +268 -0
- data/lib/pushy_client/cli.rb +168 -0
- data/lib/pushy_client/heartbeater.rb +153 -0
- data/lib/pushy_client/job_runner.rb +316 -0
- data/lib/pushy_client/periodic_reconfigurer.rb +62 -0
- data/lib/pushy_client/protocol_handler.rb +508 -0
- data/lib/pushy_client/version.rb +23 -0
- data/lib/pushy_client/whitelist.rb +66 -0
- data/lib/pushy_client/win32.rb +27 -0
- data/lib/pushy_client/windows_service.rb +253 -0
- data/omnibus/Berksfile +12 -0
- data/omnibus/Gemfile +15 -0
- data/omnibus/Gemfile.lock +232 -0
- data/omnibus/LICENSE +201 -0
- data/omnibus/README.md +141 -0
- data/omnibus/acceptance/Berksfile +6 -0
- data/omnibus/acceptance/Berksfile.lock +35 -0
- data/omnibus/acceptance/Makefile +13 -0
- data/omnibus/acceptance/README.md +29 -0
- data/omnibus/acceptance/metadata.rb +12 -0
- data/omnibus/acceptance/recipes/chef-server-user-org.rb +31 -0
- data/omnibus/config/projects/push-jobs-client.rb +83 -0
- data/omnibus/config/software/opscode-pushy-client.rb +78 -0
- data/omnibus/files/mapfiles/solaris +18 -0
- data/omnibus/files/openssl-customization/windows/ssl_env_hack.rb +34 -0
- data/omnibus/omnibus.rb +54 -0
- data/omnibus/package-scripts/push-jobs-client/postinst +55 -0
- data/omnibus/package-scripts/push-jobs-client/postrm +39 -0
- data/omnibus/resources/push-jobs-client/dmg/background.png +0 -0
- data/omnibus/resources/push-jobs-client/dmg/icon.png +0 -0
- data/omnibus/resources/push-jobs-client/msi/assets/LICENSE.rtf +197 -0
- data/omnibus/resources/push-jobs-client/msi/assets/banner_background.bmp +0 -0
- data/omnibus/resources/push-jobs-client/msi/assets/dialog_background.bmp +0 -0
- data/omnibus/resources/push-jobs-client/msi/assets/oc.ico +0 -0
- data/omnibus/resources/push-jobs-client/msi/assets/oc_16x16.ico +0 -0
- data/omnibus/resources/push-jobs-client/msi/assets/oc_32x32.ico +0 -0
- data/omnibus/resources/push-jobs-client/msi/localization-en-us.wxl.erb +26 -0
- data/omnibus/resources/push-jobs-client/msi/parameters.wxi.erb +9 -0
- data/omnibus/resources/push-jobs-client/msi/source.wxs.erb +138 -0
- data/omnibus/resources/push-jobs-client/pkg/background.png +0 -0
- data/omnibus/resources/push-jobs-client/pkg/license.html.erb +202 -0
- data/omnibus/resources/push-jobs-client/pkg/welcome.html.erb +5 -0
- data/opscode-pushy-client.gemspec +28 -0
- data/pkg/opscode-pushy-client-2.3.0.gem +0 -0
- data/spec/pushy_client/protocol_handler_spec.rb +48 -0
- data/spec/pushy_client/whitelist_spec.rb +70 -0
- data/spec/spec_helper.rb +12 -0
- metadata +235 -0
data/README.md
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# Push Jobs Client
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/chef/opscode-pushy-client.svg?branch=master)](https://travis-ci.org/chef/opscode-pushy-client)
|
4
|
+
|
5
|
+
Want to find out more about Push Jobs? Check out [docs.chef.io](https://docs.chef.io/push_jobs.html)!
|
6
|
+
|
7
|
+
## Development
|
8
|
+
### Setup Local Machine
|
9
|
+
|
10
|
+
bundle install
|
11
|
+
brew install zeromq
|
12
|
+
|
13
|
+
### Setup Chef Server w/ Push Jobs Server
|
14
|
+
1. Check out chef/chef-server and start DVM w/ Manage and Push Jobs.
|
15
|
+
```yaml
|
16
|
+
# config.yml
|
17
|
+
vm:
|
18
|
+
plugins:
|
19
|
+
chef-manage: true
|
20
|
+
push-jobs-server: true
|
21
|
+
```
|
22
|
+
Run `vagrant up` to bring up the Push Jobs Server.
|
23
|
+
|
24
|
+
2. Register you local machine as a node on the chef-server. From `chef-server/dev`, run:
|
25
|
+
```shell
|
26
|
+
vagrant ssh
|
27
|
+
sudo chef-server-ctl user-create local-dev Local Dev local@chef.io 'password' -f /installers/local-dev.pem
|
28
|
+
sudo chef-server-ctl org-create push-client-local "Local Push Client Development" -a local-dev -f /installers/push-client-local-validator.pem
|
29
|
+
```
|
30
|
+
|
31
|
+
3. Add your local machine as a node on the Chef Server.
|
32
|
+
```shell
|
33
|
+
chef-client -c .chef/client.rb
|
34
|
+
```
|
35
|
+
|
36
|
+
### Start Push Jobs Client
|
37
|
+
```shell
|
38
|
+
./bin/pushy-client -c .chef/push-jobs-client.rb
|
39
|
+
```
|
40
|
+
|
41
|
+
## Contributing
|
42
|
+
|
43
|
+
For information on contributing to this project see <https://github.com/chef/chef/blob/master/CONTRIBUTING.md>
|
data/RELEASE_PROCESS.md
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
# Push Client Release Process
|
2
|
+
|
3
|
+
## Document Purpose
|
4
|
+
|
5
|
+
The purpose of this document is to describe the current release process such that any member of the team can do a release. As we improve the automation around the release process, the document should be updated such that it always has the exact steps required to release Push Client.
|
6
|
+
|
7
|
+
This document is NOT aspirational. We have a number of automation tools that we intend to use to improve the release release process; however, many are not fully integrated with our process yet.. Do not add them to this document until they are ready to be part of the release process and can be used by any team member to perform a release.
|
8
|
+
|
9
|
+
## Prequisites
|
10
|
+
|
11
|
+
In order to release, you will need the following accounts/permissions:
|
12
|
+
|
13
|
+
- Local checkouts of the opscode-pushy-client and chef-web-downloads repositories
|
14
|
+
- Push access to the opscode-pushy-client github repository
|
15
|
+
- Chef Software, Inc Slack account
|
16
|
+
- Account on [https://discourse.chef.io](https://discourse.chef.io) using your Chef email address
|
17
|
+
- VPN account for Chef Software, Inc.
|
18
|
+
- Login for manhattan.ci.chef.co (This is linked to your github
|
19
|
+
account.)
|
20
|
+
- Access to artifactory credentials (use your LDAP credentials)
|
21
|
+
|
22
|
+
## The Process
|
23
|
+
|
24
|
+
### Testing the release
|
25
|
+
|
26
|
+
Our current support platforms are as follows:
|
27
|
+
|
28
|
+
- Debian 6, 7
|
29
|
+
- Rhel 5, 6, 7
|
30
|
+
- Ubuntu 10.04, 12.04, 14.04
|
31
|
+
- Windows 7, 8, 8.1, 10, Server 2008 R2, 2012, 2012 R2
|
32
|
+
|
33
|
+
Currently, push-client must be manually tested to verify that it behaves correctly on its supported platforms. You can use the [push-setup](https://github.com/chef/oc-pushy-pedant/tree/master/dev/push-setup) script to easily set up a push-jobs-client + push-jobs-server cluster with the desired build versions that you'd like to test.
|
34
|
+
|
35
|
+
### Preparing the release
|
36
|
+
|
37
|
+
- [ ] Double check CHANGELOG.md to ensure it includes all included changes. Update as appropriate.
|
38
|
+
|
39
|
+
### Building and Releasing the Release
|
40
|
+
|
41
|
+
- [ ] Tag the opscode-pushy-client repository with the release version: `git
|
42
|
+
tag -a VERSION_NUMBER`.
|
43
|
+
|
44
|
+
- [ ] Push the new tag: `git push origin master --tags`.
|
45
|
+
|
46
|
+
- [ ] Trigger a release build in Jenkins using the
|
47
|
+
`push-jobs-client-trigger-release` trigger. Use the tag you created
|
48
|
+
above as the GIT_REF parameter.
|
49
|
+
- Watch the [push-jobs-client-trigger-release](http://manhattan.ci.chef.co/job/push-jobs-client-trigger-release/) build. (Need to be on VPN.)
|
50
|
+
|
51
|
+
- [ ] Wait for the pipeline to complete.
|
52
|
+
- Once the build is complete, the packages will be in the [Artifactory omnibus-current-local repository](http://artifactory.chef.co/simple/omnibus-current-local/com/getchef/push-jobs-client/) (Need to be on VPN.)
|
53
|
+
|
54
|
+
- [ ] Use julia to promote the build: `@julia artifactory promote
|
55
|
+
push-jobs-client TAG`. Replace TAG with the Git tag you created in the opscode-pushy-client repo. Please do this in the
|
56
|
+
"#eng-services-support" room. Once this is done, the release is
|
57
|
+
available to the public via the APT and YUM repositories.
|
58
|
+
|
59
|
+
- [ ] Chef employees should already know a release is coming; however, as a
|
60
|
+
courtesy, drop a message in the #cft-announce slack channel that the release
|
61
|
+
is coming. Provide the release number and any highlights of the release.
|
62
|
+
|
63
|
+
- [ ] In your local checkout of the [chef-web-downloads](https://github.com/chef/chef-web-downloads) repository,
|
64
|
+
generate an update to the download page using rake:
|
65
|
+
|
66
|
+
```
|
67
|
+
git checkout -b YOUR_INITIALS/release-push-jobs-client-VERSION
|
68
|
+
export ARTIFACTORY_USERNAME="Your LDAP username"
|
69
|
+
export ARTIFACTORY_PASSWORD="Your LDAP password"
|
70
|
+
rake fetch[push-jobs-client]
|
71
|
+
git add data/
|
72
|
+
# make sure all the changes are what you expect
|
73
|
+
# write a simple commit message
|
74
|
+
git commit -v
|
75
|
+
git push origin YOUR_INITIALS/release-push-jobs-client-VERSION
|
76
|
+
```
|
77
|
+
|
78
|
+
- [ ] Open a GitHub pull request for the chef-web-downloads repository
|
79
|
+
based on the branch you just created.
|
80
|
+
|
81
|
+
- [ ] Have someone review and approve the change by adding a comment to the PR: `@delivery approve`.
|
82
|
+
- Once approved and committed to master, Delivery will deploy the change to [the acceptance Downloads page](https://downloads-acceptance.chef.io/push-jobs-client/).
|
83
|
+
|
84
|
+
- [ ] Once the change successfully completes the acceptance stage, verify the new release is visible on the acceptance Downloads page.
|
85
|
+
|
86
|
+
- [ ] Deliver the change by adding a comment to the PR: `@delivery deliver`.
|
87
|
+
- Once Delivery is complete, the new release will be live on [the production Downloads page](http://downloads.chef.io/push-jobs-client/).
|
88
|
+
|
89
|
+
- [ ] Write and then publish a Discourse post on https://discourse.chef.io
|
90
|
+
once the release is live. This post should contain a link to the downloads
|
91
|
+
page ([https://downloads.chef.io](https://downloads.chef.io)) and its contents
|
92
|
+
should be based on the information that was added to the RELEASE_NOTES.md file
|
93
|
+
in an earlier step. *The post should be published to the Chef Release
|
94
|
+
Announcements category on https://discourse.chef.io. If it is a security
|
95
|
+
release, it should also be published to the Chef Security Announcements
|
96
|
+
category.* Full details on the policy of making release announcements on
|
97
|
+
Discourse can be found on the wiki: [https://chefio.atlassian.net/wiki/display/ENG/Release+Announcements+and+Security+Alerts](https://chefio.atlassian.net/wiki/display/ENG/Release+Announcements+and+Security+Alerts)
|
98
|
+
|
99
|
+
- [ ] Let `#cft-announce` know about the release, including a link to the Discourse post.
|
100
|
+
|
101
|
+
Chef Push Jobs Client is now released.
|
102
|
+
|
103
|
+
## Post Release
|
104
|
+
|
105
|
+
- [ ] Relax 🎉
|
data/Rakefile
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Mark Anderson (<mark@opscode.com>)
|
3
|
+
# Copyright:: Copyright (c) 2012 Opscode, Inc.
|
4
|
+
# All rights reserved
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'rake'
|
8
|
+
require 'bundler/gem_tasks'
|
9
|
+
|
10
|
+
require 'rubygems/package_task'
|
11
|
+
require 'rubygems/specification'
|
12
|
+
|
13
|
+
require 'date'
|
14
|
+
|
15
|
+
gemspec = eval(File.read('opscode-pushy-client.gemspec'))
|
16
|
+
|
17
|
+
Gem::PackageTask.new(gemspec) do |pkg|
|
18
|
+
pkg.need_zip = true
|
19
|
+
pkg.need_tar = true
|
20
|
+
end
|
21
|
+
|
22
|
+
Bundler::GemHelper.install_tasks
|
23
|
+
|
24
|
+
begin
|
25
|
+
require 'rspec/core/rake_task'
|
26
|
+
|
27
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
28
|
+
spec.rspec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""]
|
29
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
30
|
+
end
|
31
|
+
|
32
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
33
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
34
|
+
spec.rcov = true
|
35
|
+
end
|
36
|
+
rescue LoadError
|
37
|
+
task :spec do
|
38
|
+
abort "RSpec is not available. (sudo) gem install rspec to run unit tests"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
task :default => [:spec]
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
4
|
+
|
5
|
+
require "rubygems"
|
6
|
+
|
7
|
+
require 'pp'
|
8
|
+
|
9
|
+
puts "# Node name '#{ENV['CHEF_PUSH_NODE_NAME']}'"
|
10
|
+
puts "# Running command with args: "
|
11
|
+
pp ARGV
|
12
|
+
puts "# As user '#{ENV['USERNAME']}'"
|
13
|
+
puts "# In directory '#{Dir.pwd}'"
|
14
|
+
puts "# Job file '#{ENV['CHEF_PUSH_JOB_FILE']}'"
|
15
|
+
puts "# Job Id '#{ENV['CHEF_PUSH_JOB_ID']}'"
|
16
|
+
puts "# Full environment"
|
17
|
+
pp ENV
|
18
|
+
|
data/bin/push-apply
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
4
|
+
|
5
|
+
require "rubygems"
|
6
|
+
require 'json'
|
7
|
+
require 'tmpdir'
|
8
|
+
require 'pp'
|
9
|
+
|
10
|
+
node = ENV['CHEF_PUSH_NODE_NAME']
|
11
|
+
job_file = ENV['CHEF_PUSH_JOB_FILE']
|
12
|
+
|
13
|
+
job_file_dir = File.dirname(job_file)
|
14
|
+
|
15
|
+
jobdata = IO.read(job_file)
|
16
|
+
|
17
|
+
filejson = JSON.parse(jobdata)
|
18
|
+
|
19
|
+
pp :keys=>filejson.keys, :format=>filejson['format']
|
20
|
+
|
21
|
+
recipe = ""
|
22
|
+
|
23
|
+
case filejson['format']
|
24
|
+
when 1
|
25
|
+
recipe = filejson['file']
|
26
|
+
else
|
27
|
+
puts "Unsupported datatype #{filejson['format']}"
|
28
|
+
exit(1)
|
29
|
+
end
|
30
|
+
|
31
|
+
prefix = File.join('chef-apply-recipe-')
|
32
|
+
recipe_path = Dir::Tmpname.create(prefix) {|p|} + ".rb"
|
33
|
+
pp :recipe_path=>recipe_path
|
34
|
+
|
35
|
+
File.open(recipe_path, 'w') do |f|
|
36
|
+
f.write(recipe)
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
puts "="*60
|
41
|
+
puts "Running chef-apply with file #{recipe_path}"
|
42
|
+
puts "="*60
|
43
|
+
|
44
|
+
$stdout.flush
|
45
|
+
#puts recipe
|
46
|
+
|
47
|
+
exec "chef-apply #{recipe_path}"
|
data/bin/pushy-client
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
4
|
+
|
5
|
+
require "rubygems"
|
6
|
+
require 'chef'
|
7
|
+
require 'chef/application/windows_service_manager'
|
8
|
+
|
9
|
+
if Chef::Platform.windows?
|
10
|
+
pushy_service = {
|
11
|
+
:service_name => "pushy-client",
|
12
|
+
:service_display_name => "Pushy Client Service",
|
13
|
+
:service_description => "Runs Opscode Pushy Client.",
|
14
|
+
:service_file_path => File.expand_path(File.join(File.dirname(__FILE__), '../lib/pushy_client/windows_service.rb'))
|
15
|
+
}
|
16
|
+
Chef::Application::WindowsServiceManager.new(pushy_service).run
|
17
|
+
else
|
18
|
+
puts "pushy-service-manager is only available on Windows platforms."
|
19
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
export PATH=/usr/local/bin:$PATH
|
4
|
+
|
5
|
+
ruby -v;
|
6
|
+
# remove the Gemfile.lock and try again if bundler fails.
|
7
|
+
# This should take care of Gemfile changes that result in "bad" bundles without forcing us to rebundle every time
|
8
|
+
bundle install --path vendor/bundle || ( rm Gemfile.lock && bundle install --path vendor/bundle )
|
9
|
+
bundle exec rspec -r rspec_junit_formatter -f RspecJunitFormatter -o test.xml -f documentation spec;
|
@@ -0,0 +1,27 @@
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
2
|
+
MIIEpAIBAAKCAQEAwxOFcrbsV7bEbqzOvW5uW5lyB23qsenlUdIGyRttqzGEaki0
|
3
|
+
1s7X+PpYy4BLfmVVmA6A6FCbL38CzzTUFX1ap6LYQR2PbytYjBjZZMUiVnjEgl12
|
4
|
+
Zd1JF8dsPMj2BgPggx5GaGLvCOsajZ0YCDgWWkoO/HAEbztFIx2jdSCyD0ZH0ep4
|
5
|
+
fSGDjmkN+5XurS0dBH8J5qPeJjriA/s/RzUbULjr3gvfg49onHxr/kTKbhc78GBO
|
6
|
+
fKSH1ftECCoWnidadW7/lfKbAZ3xiSjLsIxSKxavHMeCUSgyReDZpsFOn2Saie26
|
7
|
+
jvLxWrGyn870yIh36wMvCvWKwUQPnluSnstJxwIDAQABAoIBAFB3R++GpryTpjkk
|
8
|
+
zO50k87y34dS/qE+opn6cVQZHUalWUJiFT4Z+ho4YdInbHyJniHnsaKiRTD1Shpg
|
9
|
+
Zy8qEu/dCyjo4ZZwocjAI0Qe0Mgsbpp7pO/ltFW7q9jy6BCZHs3W+iHq1UCvgbdy
|
10
|
+
Wkxhnk7GB6J3Lk0XfLA8dIVG5EvJ798sKF4LJvnftzAjlk4L3fbbYM0odNrYZpOh
|
11
|
+
nts0+p8teSwij2jdWAN0rsfGtHQjHaHGtFrBNpj0zAefBFplQ4lp7MW1i8WSiJOf
|
12
|
+
UXD/ZAkhxvRrKpfml2s0fGe3hsVxMK1iIA7nVfX0IA3whBd8S14ywZ5bdK6wDIPl
|
13
|
+
UMyj5skCgYEA73adeMll/bGEv9h9AJe+GfSxwY74UlnzUFeJcBWkwSZbFjyv/Vh3
|
14
|
+
rzcS7cTTwNO3AF5QB/oVZLmW+w3fgNs96zyaathCvDXtKYUmmAe61b3LIzk4dqBr
|
15
|
+
7ft/s0/OsNfNxD0cbTA45sJ+5rK1jd/X6WJGdTB4I0GvIexkDT94vIsCgYEA0Iwz
|
16
|
+
/kBTyhMIwRpn+Ju3HaCfNvg2A9OAsAFjRLd/krpO6BdDBRIEyRlhjhdzD9heuD4v
|
17
|
+
d9MuOAJnD1SWItvs7fOLT4KLXmRe+CjAueu5i7mwzEEGjkeeIWfD+NDdK/1SYzKH
|
18
|
+
70bZb3cZrD+r4djmUZ54Lz3KZO4/598orDV34zUCgYEAuBMMFa9rUUrGatq1rGD4
|
19
|
+
5ubsRYfrZxJyMQ45PgnFLhyX5E4eUrdQuUWyrUeiJxYYFJZrGtao31aysqYFav4d
|
20
|
+
aNibMwqushMaDdKmyjMW8fsFTjxMJRRIIxYzIdl1XwdkyzbWxTBObUSRXDF/0mGB
|
21
|
+
jYvX8XmiwCdbws3+Uxi5bOUCgYBxlhtvfLvmUQ2wl2BPsQhAc86kEvbgiJ8LvgXC
|
22
|
+
VKuAUEdP8/OF3HWMzm0rBiyeUbvtX7lc60G+MdjOKcUIQX6/b6nN6Y1dIQ/028V0
|
23
|
+
viY2KzJXXYdjkTBYg3ril2gPYI8yBkCxm4YsRtNN1PQaM5fmlohhOqd056sY8Jvn
|
24
|
+
h8u/jQKBgQCDcJkaxdnLn0GTqFzTq7wLo/vfEYdwNsmE+F8onWUVT6L3rSQmzX2E
|
25
|
+
lbrgzy7n/eUgsd7+LFRrxpSHehY3fpIr2Z/7QdtM2O0ppZHIR1tjteoWJ27osX54
|
26
|
+
G5vZdGDsUNw54e2flS1W6ODjlTkXv1aRn+AtydZYKBfQkXg0KJjq7g==
|
27
|
+
-----END RSA PRIVATE KEY-----
|
@@ -0,0 +1,9 @@
|
|
1
|
+
-----BEGIN PUBLIC KEY-----
|
2
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwLm8nRqzKICAP9LMNtpF
|
3
|
+
5LAFbOjCRvceprp+Gs6M1xU3csU0S16ZpBUuXslIcJyOWWZtfyqW2GPb4+zNlbAQ
|
4
|
+
lsg26ngpw+XT9e4XH2ufp8xkQpwOBiA+1uo54uUj3PSxb1fySvPzpGzuhxOuGgBP
|
5
|
+
JUrE7EE0eQFl3lTFDz9EtRgYc9x9kmbf0CfxX+YdMLCTsWJKC+BmzYARtFtf6rJc
|
6
|
+
mpN0EF29kBunF2AckjF3EYm6H351BnJtCZMZn2vqBF1UPt4bdnuloUdPW2xOf0Zm
|
7
|
+
LiyfwjODDOinSTpE5E8WfU1efXST7GvYZ1CmWS41c1UZBsqjLUDDlQNM8jWmpHqb
|
8
|
+
4QIDAQAB
|
9
|
+
-----END PUBLIC KEY-----
|
data/lib/pushy_client.rb
ADDED
@@ -0,0 +1,268 @@
|
|
1
|
+
#
|
2
|
+
# Author:: John Keiser (<jkeiser@opscode.com>)
|
3
|
+
# Copyright:: Copyright (c) 2012 Opscode, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
require_relative 'pushy_client/version'
|
19
|
+
require_relative 'pushy_client/heartbeater'
|
20
|
+
require_relative 'pushy_client/job_runner'
|
21
|
+
require_relative 'pushy_client/protocol_handler'
|
22
|
+
require_relative 'pushy_client/periodic_reconfigurer'
|
23
|
+
require_relative 'pushy_client/whitelist'
|
24
|
+
require 'ohai'
|
25
|
+
require 'uuidtools'
|
26
|
+
require 'ffi-rzmq'
|
27
|
+
require 'cgi'
|
28
|
+
|
29
|
+
class PushyClient
|
30
|
+
def initialize(options)
|
31
|
+
@chef_server_url = options[:chef_server_url]
|
32
|
+
@client_name = options[:client_name] || options[:node_name]
|
33
|
+
@client_key = options[:client_key]
|
34
|
+
@node_name = options[:node_name]
|
35
|
+
@whitelist = PushyClient::Whitelist.new(options[:whitelist])
|
36
|
+
@hostname = options[:hostname]
|
37
|
+
@file_dir = options[:file_dir] || '/tmp/pushy'
|
38
|
+
@file_dir_expiry = options[:file_dir_expiry] || 86400
|
39
|
+
|
40
|
+
@allow_unencrypted = options[:allow_unencrypted] || false
|
41
|
+
@client_curve_pub_key, @client_curve_sec_key = ZMQ::Util.curve_keypair
|
42
|
+
|
43
|
+
Chef::Log.info("[#{@node_name}] using config file path: '#{Chef::Config[:config_file]}'")
|
44
|
+
|
45
|
+
if @chef_server_url =~ /\/organizations\/+([^\/]+)\/*/
|
46
|
+
@org_name = $1
|
47
|
+
else
|
48
|
+
raise "chef_server must end in /organizations/ORG_NAME"
|
49
|
+
end
|
50
|
+
|
51
|
+
@incarnation_id = UUIDTools::UUID.random_create
|
52
|
+
|
53
|
+
# State is global and persists across stops and starts
|
54
|
+
@job_runner = JobRunner.new(self)
|
55
|
+
@heartbeater = Heartbeater.new(self)
|
56
|
+
@protocol_handler = ProtocolHandler.new(self)
|
57
|
+
@periodic_reconfigurer = PeriodicReconfigurer.new(self)
|
58
|
+
@file_dir_cleaner = FileDirCleaner.new(self)
|
59
|
+
|
60
|
+
@reconfigure_lock = Mutex.new
|
61
|
+
|
62
|
+
Chef::Log.info "[#{node_name}] Using node name: #{node_name}"
|
63
|
+
Chef::Log.info "[#{node_name}] Using org name: #{org_name}"
|
64
|
+
Chef::Log.info "[#{node_name}] Using Chef server: #{chef_server_url}"
|
65
|
+
Chef::Log.info "[#{node_name}] Using private key: #{client_key}"
|
66
|
+
Chef::Log.info "[#{node_name}] Incarnation ID: #{incarnation_id}"
|
67
|
+
Chef::Log.info "[#{node_name}] Allowing fallback to unencrypted connection: #{allow_unencrypted}"
|
68
|
+
end
|
69
|
+
|
70
|
+
attr_accessor :chef_server_url
|
71
|
+
attr_accessor :client_name
|
72
|
+
attr_accessor :client_key
|
73
|
+
attr_accessor :org_name
|
74
|
+
attr_accessor :node_name
|
75
|
+
attr_accessor :hostname
|
76
|
+
attr_accessor :whitelist
|
77
|
+
attr_reader :incarnation_id
|
78
|
+
attr_reader :legacy_mode # indicate we've fallen back to 1.x
|
79
|
+
|
80
|
+
# crypto
|
81
|
+
attr_reader :client_curve_pub_key
|
82
|
+
attr_reader :client_curve_sec_key
|
83
|
+
attr_reader :allow_unencrypted
|
84
|
+
attr_reader :using_curve
|
85
|
+
|
86
|
+
#
|
87
|
+
attr_reader :file_dir
|
88
|
+
attr_reader :file_dir_expiry
|
89
|
+
|
90
|
+
attr_reader :config
|
91
|
+
|
92
|
+
def start
|
93
|
+
Chef::Log.info "[#{node_name}] Starting client ..."
|
94
|
+
|
95
|
+
@config = get_config
|
96
|
+
|
97
|
+
@job_runner.start
|
98
|
+
@protocol_handler.start
|
99
|
+
@heartbeater.start
|
100
|
+
@periodic_reconfigurer.start
|
101
|
+
@file_dir_cleaner.start
|
102
|
+
|
103
|
+
Chef::Log.info "[#{node_name}] Started client."
|
104
|
+
end
|
105
|
+
|
106
|
+
def stop
|
107
|
+
Chef::Log.info "[#{node_name}] Stopping client ..."
|
108
|
+
|
109
|
+
@job_runner.stop
|
110
|
+
@protocol_handler.stop
|
111
|
+
@heartbeater.stop
|
112
|
+
@periodic_reconfigurer.stop
|
113
|
+
@file_dir_cleaner.stop
|
114
|
+
|
115
|
+
Chef::Log.info "[#{node_name}] Stopped client."
|
116
|
+
end
|
117
|
+
|
118
|
+
def reconfigure
|
119
|
+
first = true
|
120
|
+
while !@job_runner.safe_to_reconfigure? do
|
121
|
+
Chef::Log.info "[#{node_name}] Job in flight, delaying reconfigure" if first
|
122
|
+
first = false
|
123
|
+
sleep 5
|
124
|
+
end
|
125
|
+
|
126
|
+
@reconfigure_lock.synchronize do
|
127
|
+
Chef::Log.info "[#{node_name}] Reconfiguring client / reloading keys ..."
|
128
|
+
|
129
|
+
@config = get_config
|
130
|
+
|
131
|
+
@job_runner.reconfigure
|
132
|
+
@protocol_handler.reconfigure
|
133
|
+
@heartbeater.reconfigure
|
134
|
+
@periodic_reconfigurer.reconfigure
|
135
|
+
|
136
|
+
Chef::Log.info "[#{node_name}] Reconfigured client."
|
137
|
+
end
|
138
|
+
trigger_gc
|
139
|
+
end
|
140
|
+
|
141
|
+
def trigger_reconfigure
|
142
|
+
# Many of the threads triggering a reconfigure will get destroyed DURING
|
143
|
+
# a reconfigure, so we need to spawn a separate thread to take care of it.
|
144
|
+
Thread.new do
|
145
|
+
begin
|
146
|
+
reconfigure
|
147
|
+
rescue
|
148
|
+
log_exception("Error reconfiguring", $!)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def trigger_gc
|
154
|
+
# We have a tendency to bloat up because GCs aren't forced; this tries to keep things a little bit saner.
|
155
|
+
before_stat = GC.stat()
|
156
|
+
GC.start()
|
157
|
+
after_stat = GC.stat()
|
158
|
+
stat = :count
|
159
|
+
delta = after_stat[stat] - before_stat[stat]
|
160
|
+
Chef::Log.info("[#{node_name}] Forced GC; Stat #{stat} changed #{delta}")
|
161
|
+
end
|
162
|
+
|
163
|
+
def job_state
|
164
|
+
@job_runner.job_state
|
165
|
+
end
|
166
|
+
|
167
|
+
def send_command(command, job_id, params = {})
|
168
|
+
@protocol_handler.send_command(command, job_id, params)
|
169
|
+
end
|
170
|
+
|
171
|
+
def send_heartbeat(sequence)
|
172
|
+
@protocol_handler.send_heartbeat(sequence)
|
173
|
+
end
|
174
|
+
|
175
|
+
def commit(job_id, command, opts)
|
176
|
+
@job_runner.commit(job_id, command, opts)
|
177
|
+
end
|
178
|
+
|
179
|
+
def run(job_id)
|
180
|
+
@job_runner.run(job_id)
|
181
|
+
end
|
182
|
+
|
183
|
+
def abort
|
184
|
+
@job_runner.abort
|
185
|
+
end
|
186
|
+
|
187
|
+
def heartbeat_received(incarnation_id, sequence)
|
188
|
+
@heartbeater.heartbeat_received(incarnation_id, sequence)
|
189
|
+
end
|
190
|
+
|
191
|
+
def log_exception(message, exception)
|
192
|
+
Chef::Log.error("[#{node_name}] #{message}: #{exception}\n#{exception.backtrace.join("\n")}")
|
193
|
+
end
|
194
|
+
|
195
|
+
def on_server_availability_change(&block)
|
196
|
+
@heartbeater.on_server_availability_change(&block)
|
197
|
+
end
|
198
|
+
|
199
|
+
def online?
|
200
|
+
@heartbeater.online?
|
201
|
+
end
|
202
|
+
|
203
|
+
def on_job_state_change(&block)
|
204
|
+
@job_runner.on_job_state_change(&block)
|
205
|
+
end
|
206
|
+
|
207
|
+
private
|
208
|
+
|
209
|
+
def rest
|
210
|
+
@rest ||= Chef::ServerAPI.new(chef_server_url, client_name: client_name, signing_key_filename: client_key)
|
211
|
+
end
|
212
|
+
|
213
|
+
def get_config
|
214
|
+
resource = "/pushy/config/#{node_name}"
|
215
|
+
|
216
|
+
Chef::Log.info "[#{node_name}] Retrieving configuration from #{chef_server_url}/#{resource}: ..."
|
217
|
+
esc_key = CGI::escape(@client_curve_pub_key)
|
218
|
+
version = PushyClient::PROTOCOL_VERSION
|
219
|
+
resource = "pushy/config/#{node_name}?ccpk=#{esc_key}&version=#{version}"
|
220
|
+
|
221
|
+
config = rest.get(resource)
|
222
|
+
|
223
|
+
if config.has_key?("curve_public_key")
|
224
|
+
# Version 2.0 or greater, we should use encryption
|
225
|
+
@using_curve = true
|
226
|
+
@legacy_mode = false
|
227
|
+
elsif allow_unencrypted then
|
228
|
+
@using_curve = false
|
229
|
+
@legacy_mode = true
|
230
|
+
Chef::Log.info "[#{node_name}] No key returned from server; falling back to 1.x protocol (no encryption)"
|
231
|
+
else
|
232
|
+
msg = "[#{node_name}] Exiting: No key returned from server; server may be using 1.x protocol. The config flag 'allow_unencrypted' disables encryption and allows use of 1.x server. Use with caution!"
|
233
|
+
Chef::Log.error msg
|
234
|
+
Kernel.abort msg
|
235
|
+
config = nil
|
236
|
+
end
|
237
|
+
return config
|
238
|
+
end
|
239
|
+
|
240
|
+
# XXX Should go in a separate file
|
241
|
+
class FileDirCleaner
|
242
|
+
def initialize(client)
|
243
|
+
@client = client
|
244
|
+
@expiration_time = client.file_dir_expiry
|
245
|
+
@file_dir = client.file_dir
|
246
|
+
end
|
247
|
+
|
248
|
+
def start
|
249
|
+
@thread = Thread.new { expiration_loop }
|
250
|
+
end
|
251
|
+
|
252
|
+
def stop
|
253
|
+
@thread.kill
|
254
|
+
end
|
255
|
+
|
256
|
+
private
|
257
|
+
|
258
|
+
def expiration_loop
|
259
|
+
while true do
|
260
|
+
files = Dir.glob(@file_dir + "/pushy_file*")
|
261
|
+
now = Time.now
|
262
|
+
old_files = files.select { |f| now - File.mtime(f) > @expiration_time}
|
263
|
+
File.delete(*old_files)
|
264
|
+
sleep @expiration_time
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|