Class: PushyClient

Inherits:
Object
  • Object
show all
Defined in:
lib/pushy_client/version.rb,
lib/pushy_client.rb,
lib/pushy_client/cli.rb,
lib/pushy_client/whitelist.rb,
lib/pushy_client/job_runner.rb,
lib/pushy_client/heartbeater.rb,
lib/pushy_client/windows_service.rb,
lib/pushy_client/protocol_handler.rb,
lib/pushy_client/periodic_reconfigurer.rb

Overview

This file is provided to you under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Defined Under Namespace

Classes: CLI, FileDirCleaner, Heartbeater, JobRunner, PeriodicReconfigurer, ProtocolHandler, Whitelist, WindowsService, ZmqContext

Constant Summary collapse

VERSION =
"2.3.0"
PROTOCOL_VERSION =
"2.0"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ PushyClient

Returns a new instance of PushyClient.



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/pushy_client.rb', line 30

def initialize(options)
  @chef_server_url = options[:chef_server_url]
  @client_name     = options[:client_name] || options[:node_name]
  @client_key      = options[:client_key]
  @node_name       = options[:node_name]
  @whitelist       = PushyClient::Whitelist.new(options[:whitelist])
  @hostname        = options[:hostname]
  @file_dir        = options[:file_dir] || '/tmp/pushy'
  @file_dir_expiry = options[:file_dir_expiry] || 86400

  @allow_unencrypted = options[:allow_unencrypted] || false
  @client_curve_pub_key, @client_curve_sec_key = ZMQ::Util.curve_keypair

  Chef::Log.info("[#{@node_name}] using config file path: '#{Chef::Config[:config_file]}'")

  if @chef_server_url =~ /\/organizations\/+([^\/]+)\/*/
    @org_name = $1
  else
    raise "chef_server must end in /organizations/ORG_NAME"
  end

  @incarnation_id = UUIDTools::UUID.random_create

  # State is global and persists across stops and starts
  @job_runner = JobRunner.new(self)
  @heartbeater = Heartbeater.new(self)
  @protocol_handler = ProtocolHandler.new(self)
  @periodic_reconfigurer = PeriodicReconfigurer.new(self)
  @file_dir_cleaner = FileDirCleaner.new(self)

  @reconfigure_lock = Mutex.new

  Chef::Log.info "[#{node_name}] Using node name: #{node_name}"
  Chef::Log.info "[#{node_name}] Using org name: #{org_name}"
  Chef::Log.info "[#{node_name}] Using Chef server: #{chef_server_url}"
  Chef::Log.info "[#{node_name}] Using private key: #{client_key}"
  Chef::Log.info "[#{node_name}] Incarnation ID: #{incarnation_id}"
  Chef::Log.info "[#{node_name}] Allowing fallback to unencrypted connection: #{allow_unencrypted}"
end

Instance Attribute Details

#allow_unencryptedObject (readonly)

Returns the value of attribute allow_unencrypted.



83
84
85
# File 'lib/pushy_client.rb', line 83

def allow_unencrypted
  @allow_unencrypted
end

#chef_server_urlObject

Returns the value of attribute chef_server_url.



70
71
72
# File 'lib/pushy_client.rb', line 70

def chef_server_url
  @chef_server_url
end

#client_curve_pub_keyObject (readonly)

crypto



81
82
83
# File 'lib/pushy_client.rb', line 81

def client_curve_pub_key
  @client_curve_pub_key
end

#client_curve_sec_keyObject (readonly)

Returns the value of attribute client_curve_sec_key.



82
83
84
# File 'lib/pushy_client.rb', line 82

def client_curve_sec_key
  @client_curve_sec_key
end

#client_keyObject

Returns the value of attribute client_key.



72
73
74
# File 'lib/pushy_client.rb', line 72

def client_key
  @client_key
end

#client_nameObject

Returns the value of attribute client_name.



71
72
73
# File 'lib/pushy_client.rb', line 71

def client_name
  @client_name
end

#configObject (readonly)

Returns the value of attribute config.



90
91
92
# File 'lib/pushy_client.rb', line 90

def config
  @config
end

#file_dirObject (readonly)

Returns the value of attribute file_dir.



87
88
89
# File 'lib/pushy_client.rb', line 87

def file_dir
  @file_dir
end

#file_dir_expiryObject (readonly)

Returns the value of attribute file_dir_expiry.



88
89
90
# File 'lib/pushy_client.rb', line 88

def file_dir_expiry
  @file_dir_expiry
end

#hostnameObject

Returns the value of attribute hostname.



75
76
77
# File 'lib/pushy_client.rb', line 75

def hostname
  @hostname
end

#incarnation_idObject (readonly)

Returns the value of attribute incarnation_id.



77
78
79
# File 'lib/pushy_client.rb', line 77

def incarnation_id
  @incarnation_id
end

#legacy_modeObject (readonly)

indicate we’ve fallen back to 1.x



78
79
80
# File 'lib/pushy_client.rb', line 78

def legacy_mode
  @legacy_mode
end

#node_nameObject

Returns the value of attribute node_name.



74
75
76
# File 'lib/pushy_client.rb', line 74

def node_name
  @node_name
end

#org_nameObject

Returns the value of attribute org_name.



73
74
75
# File 'lib/pushy_client.rb', line 73

def org_name
  @org_name
end

#using_curveObject (readonly)

Returns the value of attribute using_curve.



84
85
86
# File 'lib/pushy_client.rb', line 84

def using_curve
  @using_curve
end

#whitelistObject

Returns the value of attribute whitelist.



76
77
78
# File 'lib/pushy_client.rb', line 76

def whitelist
  @whitelist
end

Instance Method Details

#abortObject



183
184
185
# File 'lib/pushy_client.rb', line 183

def abort
  @job_runner.abort
end

#commit(job_id, command, opts) ⇒ Object



175
176
177
# File 'lib/pushy_client.rb', line 175

def commit(job_id, command, opts)
  @job_runner.commit(job_id, command, opts)
end

#heartbeat_received(incarnation_id, sequence) ⇒ Object



187
188
189
# File 'lib/pushy_client.rb', line 187

def heartbeat_received(incarnation_id, sequence)
  @heartbeater.heartbeat_received(incarnation_id, sequence)
end

#job_stateObject



163
164
165
# File 'lib/pushy_client.rb', line 163

def job_state
  @job_runner.job_state
end

#log_exception(message, exception) ⇒ Object



191
192
193
# File 'lib/pushy_client.rb', line 191

def log_exception(message, exception)
  Chef::Log.error("[#{node_name}] #{message}: #{exception}\n#{exception.backtrace.join("\n")}")
end

#on_job_state_change(&block) ⇒ Object



203
204
205
# File 'lib/pushy_client.rb', line 203

def on_job_state_change(&block)
  @job_runner.on_job_state_change(&block)
end

#on_server_availability_change(&block) ⇒ Object



195
196
197
# File 'lib/pushy_client.rb', line 195

def on_server_availability_change(&block)
  @heartbeater.on_server_availability_change(&block)
end

#online?Boolean

Returns:

  • (Boolean)


199
200
201
# File 'lib/pushy_client.rb', line 199

def online?
  @heartbeater.online?
end

#reconfigureObject



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/pushy_client.rb', line 118

def reconfigure
  first = true
  while !@job_runner.safe_to_reconfigure? do
    Chef::Log.info "[#{node_name}] Job in flight, delaying reconfigure" if first
    first = false
    sleep 5
  end

  @reconfigure_lock.synchronize do
    Chef::Log.info "[#{node_name}] Reconfiguring client / reloading keys ..."

    @config = get_config

    @job_runner.reconfigure
    @protocol_handler.reconfigure
    @heartbeater.reconfigure
    @periodic_reconfigurer.reconfigure

    Chef::Log.info "[#{node_name}] Reconfigured client."
  end
  trigger_gc
end

#run(job_id) ⇒ Object



179
180
181
# File 'lib/pushy_client.rb', line 179

def run(job_id)
  @job_runner.run(job_id)
end

#send_command(command, job_id, params = {}) ⇒ Object



167
168
169
# File 'lib/pushy_client.rb', line 167

def send_command(command, job_id, params = {})
  @protocol_handler.send_command(command, job_id, params)
end

#send_heartbeat(sequence) ⇒ Object



171
172
173
# File 'lib/pushy_client.rb', line 171

def send_heartbeat(sequence)
  @protocol_handler.send_heartbeat(sequence)
end

#startObject



92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/pushy_client.rb', line 92

def start
  Chef::Log.info "[#{node_name}] Starting client ..."

  @config = get_config

  @job_runner.start
  @protocol_handler.start
  @heartbeater.start
  @periodic_reconfigurer.start
  @file_dir_cleaner.start

  Chef::Log.info "[#{node_name}] Started client."
end

#stopObject



106
107
108
109
110
111
112
113
114
115
116
# File 'lib/pushy_client.rb', line 106

def stop
  Chef::Log.info "[#{node_name}] Stopping client ..."

  @job_runner.stop
  @protocol_handler.stop
  @heartbeater.stop
  @periodic_reconfigurer.stop
  @file_dir_cleaner.stop

  Chef::Log.info "[#{node_name}] Stopped client."
end

#trigger_gcObject



153
154
155
156
157
158
159
160
161
# File 'lib/pushy_client.rb', line 153

def trigger_gc
  # We have a tendency to bloat up because GCs aren't forced; this tries to keep things a little bit saner.
  before_stat = GC.stat()
  GC.start()
  after_stat = GC.stat()
  stat = :count
  delta = after_stat[stat] - before_stat[stat]
  Chef::Log.info("[#{node_name}] Forced GC; Stat #{stat} changed #{delta}")
end

#trigger_reconfigureObject



141
142
143
144
145
146
147
148
149
150
151
# File 'lib/pushy_client.rb', line 141

def trigger_reconfigure
  # Many of the threads triggering a reconfigure will get destroyed DURING
  # a reconfigure, so we need to spawn a separate thread to take care of it.
  Thread.new do
    begin
      reconfigure
    rescue
      log_exception("Error reconfiguring", $!)
    end
  end
end