Commit 1dc20627 authored by Jay Mundrawala's avatar Jay Mundrawala
Browse files

Merge pull request #3639 from chef/jdm/12.4.1

12.4.1
parents 283b8d21 42450988
......@@ -12,6 +12,7 @@ branches:
- 10-stable
- 11-stable
- 12-stable
- 12.4-stable
# do not run expensive spec tests on PRs, only on branches
script: "
......
## Unreleased
* [**Ranjib Dey**](https://github.com/ranjib):
[pr#3588](https://github.com/chef/chef/pull/3588) Count skipped resources among total resources in doc formatter
* [**John Kerry**](https://github.com/jkerry):
[pr#3539](https://github.com/chef/chef/pull/3539) Fix issue: registry_key resource is case sensitive in chef but not on windows
* [**David Eddy**](https://github.com/bahamas10):
[pr#3443](https://github.com/chef/chef/pull/3443) remove extraneous space
* [pr#3455](https://github.com/chef/chef/pull/3455) powershell_script: do not allow suppression of syntax errors
* [pr#3519](https://github.com/chef/chef/pull/3519) The wording seemed odd.
* [pr#3208](https://github.com/chef/chef/pull/3208) Missing require (require what you use).
* [pr#3449](https://github.com/chef/chef/pull/3449) correcting minor typo in user_edit knife action
* [pr#3572](https://github.com/chef/chef/pull/3572) Use windows paths without case-sensitivity.
## 12.4.1
* [**Noah Kantrowitz**](https://github.com/coderanger):
[pr#3605](https://github.com/chef/chef/pull/3605) Rework `Resource#action` to match 12.3 API
* [pr#3586](https://github.com/chef/chef/issues/3586) Fix bug preventing light weight resources from being used with heavy weight providers
* [Issue #3593](https://github.com/chef/chef/issues/3593) Fix bug where provider priority map did not take into consideration a provided block
* [pr#3630](https://github.com/chef/chef/pull/3630) Restore Chef::User and Chef::ApiClient namespace to API V0 functionality and move new functionality into Chef::UserV1 and Chef::ApiClientV1 until Chef 13.
* [pr#3611](https://github.com/chef/chef/pull/3611) Call `provides?` even if `provides` is not called
* [pr#3589](https://github.com/chef/chef/pull/3589) Fix errant bashisms
* [pr#3620](https://github.com/chef/chef/pull/3620) Fix issue where recipe names in run list mutate when version constaints are present
* [pr#3623](https://github.com/chef/chef/pull/3623) Allow LWRPs to access the real class when accessed through `Chef::Resource` and `Chef::Provider`
* [pr#3627](https://github.com/chef/chef/pull/3627) Separate priority map and DSL handler map so that `provides` has veto power over priority
* [pr#3638](https://github.com/chef/chef/pull/3638) Deprecate passing more than 1 argument to create a resource
## 12.4.0
* [**Phil Dibowitz**](https://github.com/jaymzh):
......
......@@ -15,6 +15,7 @@ branches:
only:
- master
- 12-stable
- 12.4-stable
cache:
- C:\Ruby200\lib\ruby\gems\2.0.0
......
......@@ -20,6 +20,6 @@
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
module ChefConfig
VERSION = '12.4.0'
VERSION = '12.4.1'
end
#
# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Nuo Yan (<nuo@chef.io>)
# Copyright:: Copyright (c) 2008, 2015 Chef Software, Inc.
# Author:: Adam Jacob (<adam@opscode.com>)
# Author:: Nuo Yan (<nuo@opscode.com>)
# Copyright:: Copyright (c) 2008 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
......@@ -23,18 +23,18 @@ require 'chef/mixin/from_file'
require 'chef/mash'
require 'chef/json_compat'
require 'chef/search/query'
require 'chef/exceptions'
require 'chef/mixin/api_version_request_handling'
require 'chef/server_api'
# DEPRECATION NOTE
#
# This code will be removed in Chef 13 in favor of the code in Chef::ApiClientV1,
# which will be moved to this namespace. New development should occur in
# Chef::ApiClientV1 until the time before Chef 13.
class Chef
class ApiClient
include Chef::Mixin::FromFile
include Chef::Mixin::ParamsValidate
include Chef::Mixin::ApiVersionRequestHandling
SUPPORTED_API_VERSIONS = [0,1]
# Create a new Chef::ApiClient object.
def initialize
......@@ -43,25 +43,6 @@ class Chef
@private_key = nil
@admin = false
@validator = false
@create_key = nil
end
def chef_rest_v0
@chef_rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], {:api_version => "0"})
end
def chef_rest_v1
@chef_rest_v1 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], {:api_version => "1"})
end
# will default to the current version (Chef::Authenticator::DEFAULT_SERVER_API_VERSION)
def http_api
@http_api ||= Chef::REST.new(Chef::Config[:chef_server_url])
end
# will default to the current version (Chef::Authenticator::DEFAULT_SERVER_API_VERSION)
def self.http_api
Chef::REST.new(Chef::Config[:chef_server_url])
end
# Gets or sets the client name.
......@@ -113,8 +94,7 @@ class Chef
)
end
# Private key. The server will return it as a string.
# Set to true under API V0 to have the server regenerate the default key.
# Gets or sets the private key.
#
# @params [Optional String] The string representation of the private key.
# @return [String] The current value.
......@@ -122,19 +102,7 @@ class Chef
set_or_return(
:private_key,
arg,
:kind_of => [String, TrueClass, FalseClass]
)
end
# Used to ask server to generate key pair under api V1
#
# @params [Optional True/False] Should be true or false - default is false.
# @return [True/False] The current value
def create_key(arg=nil)
set_or_return(
:create_key,
arg,
:kind_of => [ TrueClass, FalseClass ]
:kind_of => [String, FalseClass]
)
end
......@@ -145,14 +113,13 @@ class Chef
def to_hash
result = {
"name" => @name,
"public_key" => @public_key,
"validator" => @validator,
"admin" => @admin,
'json_class' => self.class.name,
"chef_type" => "client"
}
result["private_key"] = @private_key unless @private_key.nil?
result["public_key"] = @public_key unless @public_key.nil?
result["create_key"] = @create_key unless @create_key.nil?
result["private_key"] = @private_key if @private_key
result
end
......@@ -166,11 +133,10 @@ class Chef
def self.from_hash(o)
client = Chef::ApiClient.new
client.name(o["name"] || o["clientname"])
client.private_key(o["private_key"]) if o.key?("private_key")
client.public_key(o["public_key"])
client.admin(o["admin"])
client.validator(o["validator"])
client.private_key(o["private_key"]) if o.key?("private_key")
client.public_key(o["public_key"]) if o.key?("public_key")
client.create_key(o["create_key"]) if o.key?("create_key")
client
end
......@@ -182,6 +148,10 @@ class Chef
from_hash(Chef::JSONCompat.parse(j))
end
def self.http_api
Chef::ServerAPI.new(Chef::Config[:chef_server_url], {:api_version => "0"})
end
def self.reregister(name)
api_client = load(name)
api_client.reregister
......@@ -218,11 +188,11 @@ class Chef
# Save this client via the REST API, returns a hash including the private key
def save
begin
update
http_api.put("clients/#{name}", { :name => self.name, :admin => self.admin, :validator => self.validator})
rescue Net::HTTPServerException => e
# If that fails, go ahead and try and update it
if e.response.code == "404"
create
http_api.post("clients", {:name => self.name, :admin => self.admin, :validator => self.validator })
else
raise e
end
......@@ -230,95 +200,18 @@ class Chef
end
def reregister
# Try API V0 and if it fails due to V0 not being supported, raise the proper error message.
# reregister only supported in API V0 or lesser.
reregistered_self = chef_rest_v0.put("clients/#{name}", { :name => name, :admin => admin, :validator => validator, :private_key => true })
reregistered_self = http_api.put("clients/#{name}", { :name => name, :admin => admin, :validator => validator, :private_key => true })
if reregistered_self.respond_to?(:[])
private_key(reregistered_self["private_key"])
else
private_key(reregistered_self.private_key)
end
self
rescue Net::HTTPServerException => e
# if there was a 406 related to versioning, give error explaining that
# only API version 0 is supported for reregister command
if e.response.code == "406" && e.response["x-ops-server-api-version"]
version_header = Chef::JSONCompat.from_json(e.response["x-ops-server-api-version"])
min_version = version_header["min_version"]
max_version = version_header["max_version"]
error_msg = reregister_only_v0_supported_error_msg(max_version, min_version)
raise Chef::Exceptions::OnlyApiVersion0SupportedForAction.new(error_msg)
else
raise e
end
end
# Updates the client via the REST API
def update
# NOTE: API V1 dropped support for updating client keys via update (aka PUT),
# but this code never supported key updating in the first place. Since
# it was never implemented, we will simply ignore that functionality
# as it is being deprecated.
# Delete this comment after V0 support is dropped.
payload = { :name => name }
payload[:validator] = validator unless validator.nil?
# DEPRECATION
# This field is ignored in API V1, but left for backwards-compat,
# can remove after API V0 is no longer supported.
payload[:admin] = admin unless admin.nil?
begin
new_client = chef_rest_v1.put("clients/#{name}", payload)
rescue Net::HTTPServerException => e
# rescue API V0 if 406 and the server supports V0
supported_versions = server_client_api_version_intersection(e, SUPPORTED_API_VERSIONS)
raise e unless supported_versions && supported_versions.include?(0)
new_client = chef_rest_v0.put("clients/#{name}", payload)
end
new_client
end
# Create the client via the REST API
def create
payload = {
:name => name,
:validator => validator,
# this field is ignored in API V1, but left for backwards-compat,
# can remove after OSC 11 support is finished?
:admin => admin
}
begin
# try API V1
raise Chef::Exceptions::InvalidClientAttribute, "You cannot set both public_key and create_key for create." if !create_key.nil? && !public_key.nil?
payload[:public_key] = public_key unless public_key.nil?
payload[:create_key] = create_key unless create_key.nil?
new_client = chef_rest_v1.post("clients", payload)
# get the private_key out of the chef_key hash if it exists
if new_client['chef_key']
if new_client['chef_key']['private_key']
new_client['private_key'] = new_client['chef_key']['private_key']
end
new_client['public_key'] = new_client['chef_key']['public_key']
new_client.delete('chef_key')
end
rescue Net::HTTPServerException => e
# rescue API V0 if 406 and the server supports V0
supported_versions = server_client_api_version_intersection(e, SUPPORTED_API_VERSIONS)
raise e unless supported_versions && supported_versions.include?(0)
# under API V0, a key pair will always be created unless public_key is
# passed on initial POST
payload[:public_key] = public_key unless public_key.nil?
new_client = chef_rest_v0.post("clients", payload)
end
Chef::ApiClient.from_hash(self.to_hash.merge(new_client))
http_api.post("clients", self)
end
# As a string
......@@ -326,5 +219,14 @@ class Chef
"client[#{@name}]"
end
def inspect
"Chef::ApiClient name:'#{name}' admin:'#{admin.inspect}' validator:'#{validator}' " +
"public_key:'#{public_key}' private_key:'#{private_key}'"
end
def http_api
@http_api ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], {:api_version => "0"})
end
end
end
#
# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Nuo Yan (<nuo@chef.io>)
# Copyright:: Copyright (c) 2008, 2015 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.
#
require 'chef/config'
require 'chef/mixin/params_validate'
require 'chef/mixin/from_file'
require 'chef/mash'
require 'chef/json_compat'
require 'chef/search/query'
require 'chef/exceptions'
require 'chef/mixin/api_version_request_handling'
require 'chef/server_api'
require 'chef/api_client'
# COMPATIBILITY NOTE
#
# This ApiClientV1 code attempts to make API V1 requests and falls back to
# API V0 requests when it fails. New development should occur here instead
# of Chef::ApiClient as this will replace that namespace when Chef 13 is released.
#
# If you need to default to API V0 behavior (i.e. you need GET client to return
# a public key, etc), please use Chef::ApiClient and update your code to support
# API V1 before you pull in Chef 13.
class Chef
class ApiClientV1
include Chef::Mixin::FromFile
include Chef::Mixin::ParamsValidate
include Chef::Mixin::ApiVersionRequestHandling
SUPPORTED_API_VERSIONS = [0,1]
# Create a new Chef::ApiClientV1 object.
def initialize
@name = ''
@public_key = nil
@private_key = nil
@admin = false
@validator = false
@create_key = nil
end
def chef_rest_v0
@chef_rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], {:api_version => "0", :inflate_json_class => false})
end
def chef_rest_v1
@chef_rest_v1 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], {:api_version => "1", :inflate_json_class => false})
end
def self.http_api
Chef::ServerAPI.new(Chef::Config[:chef_server_url], {:api_version => "1", :inflate_json_class => false})
end
# Gets or sets the client name.
#
# @params [Optional String] The name must be alpha-numeric plus - and _.
# @return [String] The current value of the name.
def name(arg=nil)
set_or_return(
:name,
arg,
:regex => /^[\-[:alnum:]_\.]+$/
)
end
# Gets or sets whether this client is an admin.
#
# @params [Optional True/False] Should be true or false - default is false.
# @return [True/False] The current value
def admin(arg=nil)
set_or_return(
:admin,
arg,
:kind_of => [ TrueClass, FalseClass ]
)
end
# Gets or sets the public key.
#
# @params [Optional String] The string representation of the public key.
# @return [String] The current value.
def public_key(arg=nil)
set_or_return(
:public_key,
arg,
:kind_of => String
)
end
# Gets or sets whether this client is a validator.
#
# @params [Boolean] whether or not the client is a validator. If
# `nil`, retrieves the already-set value.
# @return [Boolean] The current value
def validator(arg=nil)
set_or_return(
:validator,
arg,
:kind_of => [TrueClass, FalseClass]
)
end
# Private key. The server will return it as a string.
# Set to true under API V0 to have the server regenerate the default key.
#
# @params [Optional String] The string representation of the private key.
# @return [String] The current value.
def private_key(arg=nil)
set_or_return(
:private_key,
arg,
:kind_of => [String, TrueClass, FalseClass]
)
end
# Used to ask server to generate key pair under api V1
#
# @params [Optional True/False] Should be true or false - default is false.
# @return [True/False] The current value
def create_key(arg=nil)
set_or_return(
:create_key,
arg,
:kind_of => [ TrueClass, FalseClass ]
)
end
# The hash representation of the object. Includes the name and public_key.
# Private key is included if available.
#
# @return [Hash]
def to_hash
result = {
"name" => @name,
"validator" => @validator,
"admin" => @admin,
"chef_type" => "client"
}
result["private_key"] = @private_key unless @private_key.nil?
result["public_key"] = @public_key unless @public_key.nil?
result["create_key"] = @create_key unless @create_key.nil?
result
end
# The JSON representation of the object.
#
# @return [String] the JSON string.
def to_json(*a)
Chef::JSONCompat.to_json(to_hash, *a)
end
def self.from_hash(o)
client = Chef::ApiClientV1.new
client.name(o["name"] || o["clientname"])
client.admin(o["admin"])
client.validator(o["validator"])
client.private_key(o["private_key"]) if o.key?("private_key")
client.public_key(o["public_key"]) if o.key?("public_key")
client.create_key(o["create_key"]) if o.key?("create_key")
client
end
def self.from_json(j)
Chef::ApiClientV1.from_hash(Chef::JSONCompat.from_json(j))
end
def self.reregister(name)
api_client = Chef::ApiClientV1.load(name)
api_client.reregister
end
def self.list(inflate=false)
if inflate
response = Hash.new
Chef::Search::Query.new.search(:client) do |n|
n = self.from_hash(n) if n.instance_of?(Hash)
response[n.name] = n
end
response
else
http_api.get("clients")
end
end
# Load a client by name via the API
def self.load(name)
response = http_api.get("clients/#{name}")
Chef::ApiClientV1.from_hash(response)
end
# Remove this client via the REST API
def destroy
chef_rest_v1.delete("clients/#{@name}")
end
# Save this client via the REST API, returns a hash including the private key
def save
begin
update
rescue Net::HTTPServerException => e
# If that fails, go ahead and try and update it
if e.response.code == "404"
create
else
raise e
end
end
end
def reregister
# Try API V0 and if it fails due to V0 not being supported, raise the proper error message.
# reregister only supported in API V0 or lesser.
reregistered_self = chef_rest_v0.put("clients/#{name}", { :name => name, :admin => admin, :validator => validator, :private_key => true })
if reregistered_self.respond_to?(:[])
private_key(reregistered_self["private_key"])
else
private_key(reregistered_self.private_key)
end
self
rescue Net::HTTPServerException => e
# if there was a 406 related to versioning, give error explaining that
# only API version 0 is supported for reregister command
if e.response.code == "406" && e.response["x-ops-server-api-version"]
version_header = Chef::JSONCompat.from_json(e.response["x-ops-server-api-version"])
min_version = version_header["min_version"]
max_version = version_header["max_version"]
error_msg = reregister_only_v0_supported_error_msg(max_version, min_version)
raise Chef::Exceptions::OnlyApiVersion0SupportedForAction.new(error_msg)
else
raise e
end
end
# Updates the client via the REST API
def update
# NOTE: API V1 dropped support for updating client keys via update (aka PUT),
# but this code never supported key updating in the first place. Since
# it was never implemented, we will simply ignore that functionality
# as it is being deprecated.
# Delete this comment after V0 support is dropped.
payload = { :name => name }
payload[:validator] = validator unless validator.nil?
# DEPRECATION
# This field is ignored in API V1, but left for backwards-compat,
# can remove after API V0 is no longer supported.
payload[:admin] = admin unless admin.nil?
begin
new_client = chef_rest_v1.put("clients/#{name}", payload)
rescue Net::HTTPServerException => e
# rescue API V0 if 406 and the server supports V0
supported_versions = server_client_api_version_intersection(e, SUPPORTED_API_VERSIONS)
raise e unless supported_versions && supported_versions.include?(0)
new_client = chef_rest_v0.put("clients/#{name}", payload)
end
Chef::ApiClientV1.from_hash(new_client)
end
# Create the client via the REST API
def create
payload = {
:name => name,
:validator => validator,
# this field is ignored in API V1, but left for backwards-compat,
# can remove after OSC 11 support is finished?
:admin => admin
}
begin
# try API V1
raise Chef::Exceptions::InvalidClientAttribute, "You cannot set both public_key and create_key for create." if !create_key.nil? && !public_key.nil?
payload[:public_key] = public_key unless public_key.nil?
payload[:create_key] = create_key unless create_key.nil?
new_client = chef_rest_v1.post("clients", payload)
# get the private_key out of the chef_key hash if it exists
if new_client['chef_key']
if new_client['chef_key']['private_key']
new_client['private_key'] = new_client['chef_key']['private_key']