Class: Chef::Compliance::Fetcher::ChefServer

Inherits:
InspecPlugins::Compliance::Fetcher
  • Object
show all
Defined in:
lib/chef/compliance/fetcher/chef_server.rb

Constant Summary collapse

CONFIG =
{ "insecure" => true }.freeze
CHEF_SERVER_REPORTERS =
%w{chef-server chef-server-compliance chef-server-visibility chef-server-automate}.freeze
CHEF_SERVER_FETCHERS =
%w{chef-server chef-server-compliance chef-server-visibility chef-server-automate}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.chef_server_fetcher?Boolean

Returns:

  • (Boolean)


121
122
123
# File 'lib/chef/compliance/fetcher/chef_server.rb', line 121

def self.chef_server_fetcher?
  CHEF_SERVER_FETCHERS.include?(Chef.node.attributes["audit"]["fetcher"])
end

.chef_server_reporter?Boolean

Returns:

  • (Boolean)


116
117
118
# File 'lib/chef/compliance/fetcher/chef_server.rb', line 116

def self.chef_server_reporter?
  (Array(Chef.node.attributes["audit"]["reporter"]) & CHEF_SERVER_REPORTERS).any?
end

.resolve(target) ⇒ Object

Accepts URLs to compliance profiles in one of two forms:

  • a String URL with a compliance scheme, like "compliance://namespace/profile_name"
  • a Hash with a key of compliance and a value like "compliance/profile_name" and optionally a version key with a String value


26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/chef/compliance/fetcher/chef_server.rb', line 26

def self.resolve(target)
  profile_uri = get_target_uri(target)
  return nil if profile_uri.nil?

  organization = Chef::Config[:chef_server_url].split("/").last
  owner = profile_uri.user ? "#{profile_uri.user}@#{profile_uri.host}" : profile_uri.host
  version = target[:version] if target.respond_to?(:key?)

  path_parts = [""]
  path_parts << "compliance" if chef_server_reporter? || chef_server_fetcher?
  path_parts << "organizations"
  path_parts << organization
  path_parts << "owners"
  path_parts << owner
  path_parts << "compliance"
  path_parts << profile_uri.path
  path_parts << "version/#{version}" if version
  path_parts << "tar"

  target_url = URI(Chef::Config[:chef_server_url])
  target_url.path = File.join(path_parts)
  Chef::Log.info("Fetching profile from: #{target_url}")

  new(target_url, CONFIG)
rescue URI::Error => _e
  nil
end

Instance Method Details

#download_archive_to_tempObject

Downloads archive to temporary file using a Chef::ServerAPI client so that Chef Server's header-based authentication can be used.



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/chef/compliance/fetcher/chef_server.rb', line 65

def download_archive_to_temp
  return @temp_archive_path unless @temp_archive_path.nil?

  rest = Chef::ServerAPI.new(@target, Chef::Config.merge(ssl_verify_mode: :verify_none))
  archive = with_http_rescue do
    rest.streaming_request(@target)
  end
  @archive_type = ".tar.gz"

  if archive.nil?
    path = @target.respond_to?(:path) ? @target.path : path
    raise Inspec::FetcherFailure, "Unable to find requested profile on path: '#{path}' on the #{ChefUtils::Dist::Automate::PRODUCT} system."
  end

  Inspec::Log.debug("Archive stored at temporary location: #{archive.path}")
  @temp_archive_path = archive.path
end

#handle_http_error_code(code) ⇒ Object

Raises:

  • (Inspec::FetcherFailure)


95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/chef/compliance/fetcher/chef_server.rb', line 95

def handle_http_error_code(code)
  case code
  when /401|403/
    Chef::Log.error "Auth issue: see the Compliance Phase troubleshooting documentation (http://docs.chef.io/chef_compliance_phase/#troubleshooting)."
  when /404/
    Chef::Log.error "Object does not exist on remote server."
  when /413/
    Chef::Log.error "You most likely hit the erchef request size in #{ChefUtils::Dist::Server::PRODUCT} that defaults to ~2MB. To increase this limit see the Compliance Phase troubleshooting documentation (http://docs.chef.io/chef_compliance_phase/#troubleshooting) or the Chef Infra Server configuration documentation (https://docs.chef.io/server/config_rb_server/)"
  when /429/
    Chef::Log.error "This error typically means the data sent was larger than #{ChefUtils::Dist::Automate::PRODUCT}'s limit (4 MB). Run InSpec locally to identify any controls producing large diffs."
  end
  msg = "Received HTTP error #{code}"
  Chef::Log.error msg
  raise Inspec::FetcherFailure, msg
end

#resolved_sourceObject

We want to save compliance: in the lockfile rather than url: to make sure we go back through the ComplianceAPI handling.



58
59
60
# File 'lib/chef/compliance/fetcher/chef_server.rb', line 58

def resolved_source
  { compliance: chef_server_url }
end

#to_sObject



111
112
113
# File 'lib/chef/compliance/fetcher/chef_server.rb', line 111

def to_s
  "#{ChefUtils::Dist::Server::PRODUCT}/Compliance Profile Loader"
end

#with_http_rescueObject



83
84
85
86
87
88
89
90
91
92
93
# File 'lib/chef/compliance/fetcher/chef_server.rb', line 83

def with_http_rescue
  response = yield
  if response.respond_to?(:code)
    # handle non 200 error codes, they are not raised as Net::HTTPClientException
    handle_http_error_code(response.code) if response.code.to_i >= 300
  end
  response
rescue Net::HTTPClientException => e
  Chef::Log.error e
  handle_http_error_code(e.response.code)
end