Class: GoogleComputeWindowsPassword
- Inherits:
-
Object
- Object
- GoogleComputeWindowsPassword
- Defined in:
- lib/gcewinpass/version.rb,
lib/gcewinpass.rb
Overview
- Author
-
Chef Partner Engineering (<[email protected]>)
- Copyright
-
Copyright © 2016 Chef Software, Inc.
- License
-
Apache License, Version 2.0
Licensed 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
http://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.
Constant Summary collapse
- VERSION =
'1.1.0'.freeze
Instance Attribute Summary collapse
-
#api ⇒ Object
readonly
Returns the value of attribute api.
-
#debug ⇒ Object
readonly
Returns the value of attribute debug.
-
#email ⇒ Object
readonly
Returns the value of attribute email.
-
#instance_name ⇒ Object
readonly
Returns the value of attribute instance_name.
-
#project ⇒ Object
readonly
Returns the value of attribute project.
-
#username ⇒ Object
readonly
Returns the value of attribute username.
-
#zone ⇒ Object
readonly
Returns the value of attribute zone.
Instance Method Summary collapse
- #authorization ⇒ Object
- #check_operation_for_errors!(operation_name) ⇒ Object
- #expiration_date ⇒ Object
- #exponent ⇒ Object
-
#initialize(opts = {}) ⇒ GoogleComputeWindowsPassword
constructor
A new instance of GoogleComputeWindowsPassword.
- #instance ⇒ Object
- #instance_exists? ⇒ Boolean
- #instance_metadata ⇒ Object
- #log_debug(msg) ⇒ Object
- #modulus ⇒ Object
- #new_password ⇒ Object
- #operation(operation_name) ⇒ Object
- #password_from_instance ⇒ Object
- #password_request ⇒ Object
- #password_request_metadata ⇒ Object
- #private_key ⇒ Object
- #public_key ⇒ Object
- #response_from_console_port ⇒ Object
- #timeout ⇒ Object
- #update_instance_metadata ⇒ Object
- #validate_options!(opts) ⇒ Object
- #wait_for_operation(operation_obj) ⇒ Object
Constructor Details
#initialize(opts = {}) ⇒ GoogleComputeWindowsPassword
Returns a new instance of GoogleComputeWindowsPassword.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/gcewinpass.rb', line 30 def initialize(opts = {}) (opts) @api = Google::Apis::ComputeV1::ComputeService.new @api. = @project = opts[:project] @zone = opts[:zone] @instance_name = opts[:instance_name] @email = opts[:email] @username = opts.fetch(:username, 'Administrator') @debug = opts.fetch(:debug, false) @timeout = opts.fetch(:timeout, 120) end |
Instance Attribute Details
#api ⇒ Object (readonly)
Returns the value of attribute api.
28 29 30 |
# File 'lib/gcewinpass.rb', line 28 def api @api end |
#debug ⇒ Object (readonly)
Returns the value of attribute debug.
28 29 30 |
# File 'lib/gcewinpass.rb', line 28 def debug @debug end |
#email ⇒ Object (readonly)
Returns the value of attribute email.
28 29 30 |
# File 'lib/gcewinpass.rb', line 28 def email @email end |
#instance_name ⇒ Object (readonly)
Returns the value of attribute instance_name.
28 29 30 |
# File 'lib/gcewinpass.rb', line 28 def instance_name @instance_name end |
#project ⇒ Object (readonly)
Returns the value of attribute project.
28 29 30 |
# File 'lib/gcewinpass.rb', line 28 def project @project end |
#username ⇒ Object (readonly)
Returns the value of attribute username.
28 29 30 |
# File 'lib/gcewinpass.rb', line 28 def username @username end |
#zone ⇒ Object (readonly)
Returns the value of attribute zone.
28 29 30 |
# File 'lib/gcewinpass.rb', line 28 def zone @zone end |
Instance Method Details
#authorization ⇒ Object
59 60 61 62 63 64 65 66 |
# File 'lib/gcewinpass.rb', line 59 def @authorization ||= Google::Auth.get_application_default( [ 'https://www.googleapis.com/auth/cloud-platform', 'https://www.googleapis.com/auth/compute', ] ) end |
#check_operation_for_errors!(operation_name) ⇒ Object
189 190 191 192 193 194 195 196 197 198 |
# File 'lib/gcewinpass.rb', line 189 def check_operation_for_errors!(operation_name) operation = operation(operation_name) unless operation.error.nil? errors = operation.error.errors.each_with_object([]) do |error, memo| memo << "#{error.code}: #{error.}" end raise "Operation failed: #{errors.join(', ')}" end end |
#expiration_date ⇒ Object
129 130 131 |
# File 'lib/gcewinpass.rb', line 129 def expiration_date (Time.now + 300).to_datetime.rfc3339 end |
#exponent ⇒ Object
125 126 127 |
# File 'lib/gcewinpass.rb', line 125 def exponent Base64.strict_encode64(public_key.to_der[291, 3]) end |
#instance ⇒ Object
68 69 70 |
# File 'lib/gcewinpass.rb', line 68 def instance @instance ||= api.get_instance(project, zone, instance_name) end |
#instance_exists? ⇒ Boolean
72 73 74 75 76 77 78 |
# File 'lib/gcewinpass.rb', line 72 def instance_exists? instance rescue Google::Apis::ClientError false else true end |
#instance_metadata ⇒ Object
80 81 82 |
# File 'lib/gcewinpass.rb', line 80 def instance. end |
#log_debug(msg) ⇒ Object
204 205 206 |
# File 'lib/gcewinpass.rb', line 204 def log_debug(msg) $stderr.puts msg if debug end |
#modulus ⇒ Object
121 122 123 |
# File 'lib/gcewinpass.rb', line 121 def modulus Base64.strict_encode64(public_key.to_der[33, 256]) end |
#new_password ⇒ Object
45 46 47 48 49 50 |
# File 'lib/gcewinpass.rb', line 45 def new_password raise "Unable to locate instance #{instance_name} in project #{project}, zone #{zone}" unless instance_exists? password_from_instance end |
#operation(operation_name) ⇒ Object
200 201 202 |
# File 'lib/gcewinpass.rb', line 200 def operation(operation_name) api.get_zone_operation(project, zone, operation_name) end |
#password_from_instance ⇒ Object
133 134 135 136 137 138 |
# File 'lib/gcewinpass.rb', line 133 def password_from_instance response = response_from_console_port raise 'Password agent attempted the reset but did not succeed' if response['passwordFound'] == false private_key.private_decrypt(Base64.strict_decode64(response['encryptedPassword']), OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING) end |
#password_request ⇒ Object
84 85 86 87 88 89 90 91 92 |
# File 'lib/gcewinpass.rb', line 84 def password_request { 'userName' => username, 'modulus' => modulus, 'exponent' => exponent, 'email' => email, 'expireOn' => expiration_date, } end |
#password_request_metadata ⇒ Object
94 95 96 97 98 99 |
# File 'lib/gcewinpass.rb', line 94 def Google::Apis::ComputeV1::Metadata::Item.new.tap do |item| item.key = 'windows-keys' item.value = password_request.to_json end end |
#private_key ⇒ Object
113 114 115 |
# File 'lib/gcewinpass.rb', line 113 def private_key @private_key ||= OpenSSL::PKey::RSA.new(2048) end |
#public_key ⇒ Object
117 118 119 |
# File 'lib/gcewinpass.rb', line 117 def public_key @public_key ||= private_key.public_key end |
#response_from_console_port ⇒ Object
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/gcewinpass.rb', line 140 def response_from_console_port log_debug('fetching password from console port') Timeout.timeout(timeout) do loop do api.get_instance_serial_port_output(project, zone, instance_name, port: 4).contents.lines.reverse_each do |line| line.strip! begin event = JSON.parse(line) rescue JSON::ParserError next end if event['modulus'] == modulus && event['exponent'] == exponent log_debug('modulus and exponent found - returning event') return event end end log_debug('event not found, sleeping...') sleep 5 end end rescue Timeout::Error raise Timeout::Error, 'Timeout while waiting for password agent to perform password reset' end |
#timeout ⇒ Object
208 209 210 |
# File 'lib/gcewinpass.rb', line 208 def timeout @timeout.to_i end |
#update_instance_metadata ⇒ Object
101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/gcewinpass.rb', line 101 def .items = [] if .items.nil? .items = .items.select { |item| item.key != 'windows-keys' } .items << log_debug("Updating instance #{instance_name} metadata with: #{.inspect}") wait_for_operation(api.(project, zone, instance_name, )) log_debug('Instance metadata updated.') end |
#validate_options!(opts) ⇒ Object
52 53 54 55 56 57 |
# File 'lib/gcewinpass.rb', line 52 def (opts) raise 'Project not specified' unless opts[:project] raise 'Zone not specified' unless opts[:zone] raise 'Instance name not specified' unless opts[:instance_name] raise 'Email address of GCE user not specified' unless opts[:email] end |
#wait_for_operation(operation_obj) ⇒ Object
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/gcewinpass.rb', line 168 def wait_for_operation(operation_obj) operation_name = operation_obj.name begin Timeout.timeout(timeout) do loop do operation = operation(operation_name) log_debug("Current operation status: #{operation.status}") break if operation.status == 'DONE' sleep 2 end end rescue Timeout::Error raise Timeout::Error, 'Timeout while performing GCE API operation' end check_operation_for_errors!(operation_name) log_debug('Operation completed successfully.') end |