Class: ChefDK::Policyfile::Uploader

Inherits:
Object
  • Object
show all
Defined in:
lib/chef-dk/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
# File 'lib/chef-dk/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

  @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-dk/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-dk/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-dk/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-dk/policyfile/uploader.rb', line 35

def ui
  @ui
end

Instance Method Details

#compat_mode_cookbook_exists_on_remote?(cookbook) ⇒ Boolean

Returns:

  • (Boolean)


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

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.



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

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



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

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



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

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

#data_bag_item_createObject



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

def data_bag_item_create
  policy_id = "#{policy_name}-#{policy_group}"
  lock_data = policyfile_lock.to_lock.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



146
147
148
# File 'lib/chef-dk/policyfile/uploader.rb', line 146

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

#load_cookbooks_in_compat_modeObject



170
171
172
173
174
175
# File 'lib/chef-dk/policyfile/uploader.rb', line 170

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



163
164
165
166
167
168
# File 'lib/chef-dk/policyfile/uploader.rb', line 163

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)


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

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



47
48
49
# File 'lib/chef-dk/policyfile/uploader.rb', line 47

def policy_name
  policyfile_lock.name
end

#remote_already_has_cookbook?(cookbook) ⇒ Boolean

Returns:

  • (Boolean)


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

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



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

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

  if !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



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

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



75
76
77
# File 'lib/chef-dk/policyfile/uploader.rb', line 75

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

#uploaderObject



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

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)


177
178
179
# File 'lib/chef-dk/policyfile/uploader.rb', line 177

def using_policy_document_native_api?
  @policy_document_native_api
end