Class: ChefCLI::Policyfile::Uploader

Inherits:
Object
  • Object
show all
Defined in:
lib/chef-cli/policyfile/uploader.rb

Defined Under Namespace

Classes: LockedCookbookForUpload

Constant Summary collapse

COMPAT_MODE_DATA_BAG_NAME =
"policyfiles".freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(policyfile_lock, policy_group, ui: nil, http_client: nil, policy_document_native_api: false) ⇒ Uploader

Returns a new instance of Uploader.



37
38
39
40
41
42
43
44
45
46
# File 'lib/chef-cli/policyfile/uploader.rb', line 37

def initialize(policyfile_lock, policy_group, ui: nil, http_client: nil, policy_document_native_api: false)
  @policyfile_lock = policyfile_lock
  @policy_group = policy_group
  @http_client = http_client
  @ui = ui || UI.null
  @policy_document_native_api = policy_document_native_api

  @policy_lock_for_transport = nil
  @cookbook_versions_for_policy = nil
end

Instance Attribute Details

#http_clientObject (readonly)

Returns the value of attribute http_client.



34
35
36
# File 'lib/chef-cli/policyfile/uploader.rb', line 34

def http_client
  @http_client
end

#policy_groupObject (readonly)

Returns the value of attribute policy_group.



33
34
35
# File 'lib/chef-cli/policyfile/uploader.rb', line 33

def policy_group
  @policy_group
end

#policyfile_lockObject (readonly)

Returns the value of attribute policyfile_lock.



32
33
34
# File 'lib/chef-cli/policyfile/uploader.rb', line 32

def policyfile_lock
  @policyfile_lock
end

#uiObject (readonly)

Returns the value of attribute ui.



35
36
37
# File 'lib/chef-cli/policyfile/uploader.rb', line 35

def ui
  @ui
end

Instance Method Details

#compat_mode_cookbook_exists_on_remote?(cookbook) ⇒ Boolean

Returns:

  • (Boolean)


141
142
143
144
145
# File 'lib/chef-cli/policyfile/uploader.rb', line 141

def compat_mode_cookbook_exists_on_remote?(cookbook)
  existing_cookbook_on_remote[cookbook.name.to_s]["versions"].any? do |cookbook_info|
    cookbook_info["version"] == cookbook.version
  end
end

#cookbook_versions_for_policyObject

An Array of Chef::CookbookVersion objects representing the full set that the policyfile lock requires.



153
154
155
156
157
158
159
160
161
162
163
# File 'lib/chef-cli/policyfile/uploader.rb', line 153

def cookbook_versions_for_policy
  return @cookbook_versions_for_policy if @cookbook_versions_for_policy

  policyfile_lock.validate_cookbooks!
  @cookbook_versions_for_policy =
    if using_policy_document_native_api?
      load_cookbooks_in_native_mode
    else
      load_cookbooks_in_compat_mode
    end
end

#cookbook_versions_to_uploadObject



112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/chef-cli/policyfile/uploader.rb', line 112

def cookbook_versions_to_upload
  cookbook_versions_for_policy.inject([]) do |versions_to_upload, cookbook_with_lock|
    cb = cookbook_with_lock.cookbook
    # When we abandon custom identifier support in favor of the one true
    # hash, identifier generation code can be moved into chef proper and
    # this can be removed.
    cb.identifier = cookbook_with_lock.lock.identifier

    versions_to_upload << cb unless remote_already_has_cookbook?(cb)
    versions_to_upload
  end
end

#data_bag_createObject



80
81
82
83
84
# File 'lib/chef-cli/policyfile/uploader.rb', line 80

def data_bag_create
  http_client.post("data", { "name" => COMPAT_MODE_DATA_BAG_NAME })
rescue Net::HTTPClientException => e
  raise e unless e.response.code == "409"
end

#data_bag_item_createObject



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/chef-cli/policyfile/uploader.rb', line 86

def data_bag_item_create
  policy_id = "#{policy_name}-#{policy_group}"
  lock_data = policy_lock_for_transport.dup

  lock_data["id"] = policy_id

  data_item = {
    "id" => policy_id,
    "name" => "data_bag_item_#{COMPAT_MODE_DATA_BAG_NAME}_#{policy_id}",
    "data_bag" => COMPAT_MODE_DATA_BAG_NAME,
    "raw_data" => lock_data,
    # we'd prefer to leave this out, but the "compatibility mode"
    # implementation in chef-client relies on magical class inflation
    "json_class" => "Chef::DataBagItem",
  }

  upload_lockfile_as_data_bag_item(policy_id, data_item)
  ui.msg("Policy uploaded as data bag item #{COMPAT_MODE_DATA_BAG_NAME}/#{policy_id}")
  true
end

#existing_cookbook_on_remoteObject



147
148
149
# File 'lib/chef-cli/policyfile/uploader.rb', line 147

def existing_cookbook_on_remote
  @existing_cookbook_on_remote ||= http_client.get(list_cookbooks_url)
end

#load_cookbooks_in_compat_modeObject



172
173
174
175
176
177
# File 'lib/chef-cli/policyfile/uploader.rb', line 172

def load_cookbooks_in_compat_mode
  policyfile_lock.cookbook_locks.map do |name, lock|
    cb = ReadCookbookForCompatModeUpload.load(name, lock.dotted_decimal_identifier, lock.cookbook_path)
    LockedCookbookForUpload.new(cb, lock)
  end
end

#load_cookbooks_in_native_modeObject



165
166
167
168
169
170
# File 'lib/chef-cli/policyfile/uploader.rb', line 165

def load_cookbooks_in_native_mode
  policyfile_lock.cookbook_locks.map do |name, lock|
    cb = CookbookLoaderWithChefignore.load(name, lock.cookbook_path)
    LockedCookbookForUpload.new(cb, lock)
  end
end

#native_mode_cookbook_exists_on_remote?(cookbook) ⇒ Boolean

Returns:

  • (Boolean)


135
136
137
138
139
# File 'lib/chef-cli/policyfile/uploader.rb', line 135

def native_mode_cookbook_exists_on_remote?(cookbook)
  existing_cookbook_on_remote[cookbook.name.to_s]["versions"].any? do |cookbook_info|
    cookbook_info["identifier"] == cookbook.identifier
  end
end

#policy_nameObject



48
49
50
# File 'lib/chef-cli/policyfile/uploader.rb', line 48

def policy_name
  policyfile_lock.name
end

#remote_already_has_cookbook?(cookbook) ⇒ Boolean

Returns:

  • (Boolean)


125
126
127
128
129
130
131
132
133
# File 'lib/chef-cli/policyfile/uploader.rb', line 125

def remote_already_has_cookbook?(cookbook)
  return false unless existing_cookbook_on_remote.key?(cookbook.name.to_s)

  if using_policy_document_native_api?
    native_mode_cookbook_exists_on_remote?(cookbook)
  else
    compat_mode_cookbook_exists_on_remote?(cookbook)
  end
end

#uploadObject



52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/chef-cli/policyfile/uploader.rb', line 52

def upload
  ui.msg("Uploading policy #{policy_name} (#{short_revision_id}) to policy group #{policy_group}")

  unless using_policy_document_native_api?
    ui.msg(<<~DRAGONS)
      WARN: Uploading policy to policy group #{policy_group} in compatibility mode.
      Cookbooks will be uploaded with very large version numbers, which may be picked
      up by existing nodes.
    DRAGONS
  end

  upload_cookbooks
  upload_policy
end

#upload_policyObject



67
68
69
70
71
72
73
74
# File 'lib/chef-cli/policyfile/uploader.rb', line 67

def upload_policy
  if using_policy_document_native_api?
    upload_policy_native
  else
    data_bag_create
    data_bag_item_create
  end
end

#upload_policy_nativeObject



76
77
78
# File 'lib/chef-cli/policyfile/uploader.rb', line 76

def upload_policy_native
  http_client.put("/policy_groups/#{policy_group}/policies/#{policy_name}", policy_lock_for_transport)
end

#uploaderObject



107
108
109
110
# File 'lib/chef-cli/policyfile/uploader.rb', line 107

def uploader
  # TODO: uploader runs cookbook validation; we want to do this at a different time.
  @uploader ||= Chef::CookbookUploader.new(cookbook_versions_to_upload, rest: http_client, policy_mode: using_policy_document_native_api?)
end

#using_policy_document_native_api?Boolean

Returns:

  • (Boolean)


179
180
181
# File 'lib/chef-cli/policyfile/uploader.rb', line 179

def using_policy_document_native_api?
  @policy_document_native_api
end