opscode-pushy-client 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +88 -0
  3. data/Gemfile +20 -0
  4. data/Gemfile.lock +242 -0
  5. data/LICENSE +201 -0
  6. data/README.md +43 -0
  7. data/RELEASE_PROCESS.md +105 -0
  8. data/Rakefile +42 -0
  9. data/bin/print_execution_environment +18 -0
  10. data/bin/push-apply +47 -0
  11. data/bin/pushy-client +8 -0
  12. data/bin/pushy-service-manager +19 -0
  13. data/jenkins/jenkins_run_tests.sh +9 -0
  14. data/keys/client_private.pem +27 -0
  15. data/keys/server_public.pem +9 -0
  16. data/lib/pushy_client.rb +268 -0
  17. data/lib/pushy_client/cli.rb +168 -0
  18. data/lib/pushy_client/heartbeater.rb +153 -0
  19. data/lib/pushy_client/job_runner.rb +316 -0
  20. data/lib/pushy_client/periodic_reconfigurer.rb +62 -0
  21. data/lib/pushy_client/protocol_handler.rb +508 -0
  22. data/lib/pushy_client/version.rb +23 -0
  23. data/lib/pushy_client/whitelist.rb +66 -0
  24. data/lib/pushy_client/win32.rb +27 -0
  25. data/lib/pushy_client/windows_service.rb +253 -0
  26. data/omnibus/Berksfile +12 -0
  27. data/omnibus/Gemfile +15 -0
  28. data/omnibus/Gemfile.lock +232 -0
  29. data/omnibus/LICENSE +201 -0
  30. data/omnibus/README.md +141 -0
  31. data/omnibus/acceptance/Berksfile +6 -0
  32. data/omnibus/acceptance/Berksfile.lock +35 -0
  33. data/omnibus/acceptance/Makefile +13 -0
  34. data/omnibus/acceptance/README.md +29 -0
  35. data/omnibus/acceptance/metadata.rb +12 -0
  36. data/omnibus/acceptance/recipes/chef-server-user-org.rb +31 -0
  37. data/omnibus/config/projects/push-jobs-client.rb +83 -0
  38. data/omnibus/config/software/opscode-pushy-client.rb +78 -0
  39. data/omnibus/files/mapfiles/solaris +18 -0
  40. data/omnibus/files/openssl-customization/windows/ssl_env_hack.rb +34 -0
  41. data/omnibus/omnibus.rb +54 -0
  42. data/omnibus/package-scripts/push-jobs-client/postinst +55 -0
  43. data/omnibus/package-scripts/push-jobs-client/postrm +39 -0
  44. data/omnibus/resources/push-jobs-client/dmg/background.png +0 -0
  45. data/omnibus/resources/push-jobs-client/dmg/icon.png +0 -0
  46. data/omnibus/resources/push-jobs-client/msi/assets/LICENSE.rtf +197 -0
  47. data/omnibus/resources/push-jobs-client/msi/assets/banner_background.bmp +0 -0
  48. data/omnibus/resources/push-jobs-client/msi/assets/dialog_background.bmp +0 -0
  49. data/omnibus/resources/push-jobs-client/msi/assets/oc.ico +0 -0
  50. data/omnibus/resources/push-jobs-client/msi/assets/oc_16x16.ico +0 -0
  51. data/omnibus/resources/push-jobs-client/msi/assets/oc_32x32.ico +0 -0
  52. data/omnibus/resources/push-jobs-client/msi/localization-en-us.wxl.erb +26 -0
  53. data/omnibus/resources/push-jobs-client/msi/parameters.wxi.erb +9 -0
  54. data/omnibus/resources/push-jobs-client/msi/source.wxs.erb +138 -0
  55. data/omnibus/resources/push-jobs-client/pkg/background.png +0 -0
  56. data/omnibus/resources/push-jobs-client/pkg/license.html.erb +202 -0
  57. data/omnibus/resources/push-jobs-client/pkg/welcome.html.erb +5 -0
  58. data/opscode-pushy-client.gemspec +28 -0
  59. data/pkg/opscode-pushy-client-2.3.0.gem +0 -0
  60. data/spec/pushy_client/protocol_handler_spec.rb +48 -0
  61. data/spec/pushy_client/whitelist_spec.rb +70 -0
  62. data/spec/spec_helper.rb +12 -0
  63. metadata +235 -0
@@ -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>
@@ -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 🎉
@@ -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
+
@@ -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}"
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
4
+
5
+ require "rubygems"
6
+ require_relative '../lib/pushy_client/cli'
7
+
8
+ PushyClient::CLI.new.run
@@ -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-----
@@ -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