Class: Chef::ChefFS::FileSystem::ChefServer::PolicyGroupEntry

Inherits:
RestListEntry show all
Defined in:
lib/chef/chef_fs/file_system/chef_server/policy_group_entry.rb

Overview

Represents an entire policy group. Server path: /organizations/ORG/policy_groups/GROUP Repository path: policy_groups\GROUP.json Format: { "policies": { "a": { "revision_id": "1.0.0" } } }

Instance Attribute Summary

Attributes inherited from BaseFSObject

#name, #parent, #path

Instance Method Summary collapse

Methods inherited from RestListEntry

#_read_json, #api_child_name, #api_error_text, #api_path, #chef_object, #compare_to, #data_handler, #delete, #display_name, #display_path, #environment, #exists?, #initialize, #minimize_value, #normalize_value, #org, #read, #rest

Methods inherited from BaseFSObject

#can_have_child?, #chef_object, #child, #children, #compare_to, #create_child, #delete, #dir?, #exists?, #initialize, #path_for_printing, #read, #root

Constructor Details

This class inherits a constructor from Chef::ChefFS::FileSystem::ChefServer::RestListEntry

Instance Method Details

#write(file_contents) ⇒ Object

write is different. For each policy:

  • PUT /organizations/ORG/policy_groups/GROUP/policies/POLICY For each policy on the server but not the client:
  • DELETE /organizations/ORG/policy_groups/GROUP/policies/POLICY If the server has associations for a, b and c, And the client wants associations for a, x and y, We must PUT a, x and y And DELETE b and c


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/chef/chef_fs/file_system/chef_server/policy_group_entry.rb', line 50

def write(file_contents)
  # Parse the contents to ensure they are valid JSON
  begin
    object = Chef::JSONCompat.parse(file_contents)
  rescue Chef::Exceptions::JSON::ParseError => e
    raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Parse error reading JSON creating child '#{name}': #{e}")
  end

  if data_handler
    object = data_handler.normalize_for_put(object, self)
    data_handler.verify_integrity(object, self) do |error|
      raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, nil, "Error creating '#{name}': #{error}")
    end
  end

  begin

    # this should all get carted to PolicyGroupEntry#write.

    # the server demands the full policy data, but we want users' local policy_group documents to just
    # have the data you'd get from GET /policy_groups/POLICY_GROUP. so we try to fetch that.

    # ordinarily this would be POST to the normal URL, but we do PUT to
    # /organizations/{organization}/policy_groups/{policy_group}/policies/{policy_name} with the full
    # policy data, for each individual policy.
    policy_datas = {}

    object["policies"].each do |policy_name, policy_data|
      policy_path = "/policies/#{policy_name}/revisions/#{policy_data["revision_id"]}"

      get_data =
        begin
          rest.get(policy_path)
        rescue Net::HTTPClientException => e
          raise "Could not find policy '#{policy_name}'' with revision '#{policy_data["revision_id"]}'' on the server"
        end

      # GET policy data
      server_policy_data = Chef::JSONCompat.parse(get_data)

      # if it comes back 404, raise an Exception with "Policy file X does not exist with revision Y on the server"

      # otherwise, add it to the list of policyfile datas.
      policy_datas[policy_name] = server_policy_data
    end

    begin
      existing_group = Chef::JSONCompat.parse(read)
    rescue NotFoundError
      # It's OK if the group doesn't already exist, just means no existing policies
    end

    # now we have the fullpolicy data for each policies, which is what the PUT endpoint demands.
    policy_datas.each do |policy_name, policy_data|
      # PUT /organizations/ORG/policy_groups/GROUP/policies/NAME
      rest.put("#{api_path}/policies/#{policy_name}", policy_data)
    end

    # Now we need to remove any policies that are *not* in our current group.
    if existing_group && existing_group["policies"]
      (existing_group["policies"].keys - policy_datas.keys).each do |policy_name|
        rest.delete("#{api_path}/policies/#{policy_name}")
      end
    end

  rescue Timeout::Error => e
    raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Timeout creating '#{name}': #{e}")
  rescue Net::HTTPClientException => e
    # 404 = NotFoundError
    if e.response.code == "404"
      raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
    # 409 = AlreadyExistsError
    elsif $!.response.code == "409"
      raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self, e, "Failure creating '#{name}': #{path}/#{name} already exists")
    # Anything else is unexpected (OperationFailedError)
    else
      raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Failure creating '#{name}': #{e.message}")
    end
  end

  self
end