Project

General

Profile

Revision 611959a3

Added by Thomas McKay over 5 years ago

fixes #16281 - add --itemized-subscriptions to activation-keys

View differences:

lib/hammer_cli_csv/activation_keys.rb
1 1
module HammerCLICsv
2 2
  class CsvCommand
3 3
    class ActivationKeysCommand < BaseCommand
4
      include ::HammerCLICsv::Utils::Subscriptions
5

  
4 6
      command_name 'activation-keys'
5 7
      desc         _('import or export activation keys')
6 8

  
9
      def self.supported?
10
        true
11
      end
12

  
13
      option %w(--itemized-subscriptions), :flag, _('Export one subscription per row, only process update subscriptions on import')
14

  
7 15
      ORGANIZATION = 'Organization'
8 16
      DESCRIPTION = 'Description'
9 17
      LIMIT = 'Limit'
......
13 21
      SERVICELEVEL = "Service Level"
14 22
      RELEASEVER = "Release Version"
15 23
      AUTOATTACH = "Auto-Attach"
16
      SUBSCRIPTIONS = 'Subscriptions'
17 24

  
18 25
      def export(csv)
19
        csv << [NAME, ORGANIZATION, DESCRIPTION, LIMIT, ENVIRONMENT, CONTENTVIEW,
20
                HOSTCOLLECTIONS, AUTOATTACH, SERVICELEVEL, RELEASEVER, SUBSCRIPTIONS]
26
        if option_itemized_subscriptions?
27
          export_itemized_subscriptions csv
28
        else
29
          export_all csv
30
        end
31
      end
32

  
33
      def export_itemized_subscriptions(csv)
34
        csv << shared_headers + [Utils::Subscriptions::SUBS_NAME, Utils::Subscriptions::SUBS_TYPE,
35
                                 Utils::Subscriptions::SUBS_QUANTITY, Utils::Subscriptions::SUBS_SKU,
36
                                 Utils::Subscriptions::SUBS_CONTRACT, Utils::Subscriptions::SUBS_ACCOUNT,
37
                                 Utils::Subscriptions::SUBS_START, Utils::Subscriptions::SUBS_END]
38
        iterate_activationkeys(csv) do |activationkey|
39
          columns = shared_columns(activationkey)
40
          @api.resource(:subscriptions).call(:index, {
41
              'organization_id' => activationkey['organization']['id'],
42
              'activation_key_id' => activationkey['id']
43
          })['results'].collect do |subscription|
44
            subscription_type = subscription['product_id'].to_i == 0 ? 'Red Hat' : 'Custom'
45
            subscription_type += ' Guest' if subscription['type'] == 'STACK_DERIVED'
46
            subscription_type += ' Temporary' if subscription['type'] == 'UNMAPPED_GUEST'
47
            amount = (subscription['quantity_attached'].nil? || subscription['quantity_attached'] < 1) ? 'Automatic' : subscription['quantity_attached']
48
            csv << columns +
49
              [subscription['product_name'], subscription_type, amount,
50
               subscription['product_id'], subscription['contract_number'], subscription['account_number'],
51
               DateTime.parse(subscription['start_date']),
52
               DateTime.parse(subscription['end_date'])]
53
          end
54
        end
55
      end
56

  
57
      def export_all(csv)
58
        csv << shared_headers + [SUBSCRIPTIONS]
59
        iterate_activationkeys(csv) do |activationkey|
60
          subscriptions = CSV.generate do |column|
61
            column << @api.resource(:subscriptions).call(:index, {
62
                          'organization_id' => activationkey['organization']['id'],
63
                          'activation_key_id' => activationkey['id']
64
                      })['results'].collect do |subscription|
65
              amount = (subscription['quantity_attached'].nil? || subscription['quantity_attached'] < 1) ? 'Automatic' : subscription['quantity_attached']
66
              "#{amount}"\
67
              "|#{subscription['product_id']}"\
68
              "|#{subscription['product_name']}"\
69
              "|#{subscription['contract_number']}|#{subscription['account_number']}"
70
            end
71
          end
72
          subscriptions.delete!("\n")
73
          csv << shared_columns(activationkey) + [subscriptions]
74
        end
75
      end
76

  
77
      def iterate_activationkeys(csv)
21 78
        @api.resource(:organizations).call(:index, {
22 79
            :per_page => 999999
23 80
        })['results'].each do |organization|
......
27 84
              'per_page' => 999999,
28 85
              'organization_id' => organization['id']
29 86
          })['results'].each do |activationkey|
30
            name = namify(activationkey['name'])
31
            count = 1
32
            description = activationkey['description']
33
            limit = activationkey['unlimited_content_hosts'] ? 'Unlimited' : activationkey['max_content_hosts']
34
            environment = activationkey['environment']['label']
35
            contentview = activationkey['content_view']['name']
36
            hostcollections = export_column(activationkey, 'host_collections', 'name')
37
            autoattach = activationkey['auto_attach'] ? 'Yes' : 'No'
38
            servicelevel = activationkey['service_level']
39
            releasever = activationkey['release_version']
40
            subscriptions = CSV.generate do |column|
41
              column << @api.resource(:subscriptions).call(:index, {
42
                            'organization_id' => organization['id'],
43
                            'activation_key_id' => activationkey['id']
44
                        })['results'].collect do |subscription|
45
                amount = subscription['amount'] == 0 ? 'Automatic' : subscription['amount']
46
                sku = subscription['product_id'].match(/\A[0-9]/) ? 'Custom' : subscription['product_id']
47
                "#{amount}|#{sku}|#{subscription['product_name']}"
48
              end
49
            end
50
            subscriptions.delete!("\n")
51
            csv << [name, count, organization['name'], description, limit, environment, contentview,
52
                    hostcollections, servicelevel, releasever, autoattach, subscriptions]
87
            yield activationkey
53 88
          end
54 89
        end
55 90
      end
......
58 93
        @existing = {}
59 94

  
60 95
        thread_import do |line|
61
          create_activationkeys_from_csv(line)
96
          create_from_csv(line)
62 97
        end
63 98
      end
64 99

  
65
      def create_activationkeys_from_csv(line)
100
      def create_from_csv(line)
66 101
        return if option_organization && line[ORGANIZATION] != option_organization
67 102

  
68
        if !@existing[line[ORGANIZATION]]
69
          @existing[line[ORGANIZATION]] = {}
70
          @api.resource(:activation_keys).call(:index, {
71
              'per_page' => 999999,
72
              'organization_id' => foreman_organization(:name => line[ORGANIZATION])
73
          })['results'].each do |activationkey|
74
            @existing[line[ORGANIZATION]][activationkey['name']] = activationkey['id'] if activationkey
75
          end
76
        end
103
        update_existing(line)
77 104

  
78 105
        count(line[COUNT]).times do |number|
79 106
          name = namify(line[NAME], number)
80 107

  
81
          params = {
82
                     'organization_id' => foreman_organization(:name => line[ORGANIZATION]),
83
                     'name' => name,
84
                     'environment_id' => lifecycle_environment(line[ORGANIZATION],
85
                                                               :name => line[ENVIRONMENT]),
86
                     'content_view_id' => katello_contentview(line[ORGANIZATION],
87
                                                              :name => line[CONTENTVIEW]),
88
                     'description' => line[DESCRIPTION],
89
                     'unlimited_content_hosts' => (line[LIMIT] == 'Unlimited') ? true : false,
90
                     'max_content_hosts' => (line[LIMIT] == 'Unlimited') ? nil : line[LIMIT].to_i
91
                   }
92
          params['auto_attach'] = (line[AUTOATTACH] == 'Yes' ? true : false) if params['auto_attach']
93
          params['service_level'] = line[SERVICELEVEL].nil? || line[SERVICELEVEL].empty? ? nil : line[SERVICELEVEL]
94
          params['release_version'] = line[RELEASEVER].nil? || line[RELEASEVER].empty? ? nil : line[RELEASEVER]
95
          if !@existing[line[ORGANIZATION]].include? name
96
            print _("Creating activation key '%{name}'...") % {:name => name} if option_verbose?
97
            activationkey = @api.resource(:activation_keys).call(:create, params)
98
            @existing[line[ORGANIZATION]][activationkey['name']] = activationkey['id']
108
          if option_itemized_subscriptions?
109
            update_itemized_subscriptions(name, line)
99 110
          else
100
            print _("Updating activation key '%{name}'...") % {:name => name} if option_verbose?
101
            params['id'] = @existing[line[ORGANIZATION]][name]
102
            activationkey = @api.resource(:activation_keys).call(:update, params)
111
            update_or_create(name, line)
103 112
          end
113
        end
114
      end
115

  
116
      def update_itemized_subscriptions(name, line)
117
        raise _("Activation key '%{name}' must already exist with --itemized_subscriptions") % {:name => name} unless @existing[line[ORGANIZATION]].include? name
104 118

  
105
          update_subscriptions(activationkey, line)
106
          update_groups(activationkey, line)
119
        print(_("Updating subscriptions for activation key '%{name}'...") % {:name => name}) if option_verbose?
120
        activationkey = @api.resource(:activation_keys).call(:show, {:id => @existing[line[ORGANIZATION]][name]})
121
        update_subscriptions(activationkey, line, false)
122
        puts _('done') if option_verbose?
123
      end
107 124

  
108
          puts _('done') if option_verbose?
125
      def update_or_create(name, line)
126
        params = {
127
                   'organization_id' => foreman_organization(:name => line[ORGANIZATION]),
128
                   'name' => name,
129
                   'environment_id' => lifecycle_environment(line[ORGANIZATION],
130
                                                             :name => line[ENVIRONMENT]),
131
                   'content_view_id' => katello_contentview(line[ORGANIZATION],
132
                                                            :name => line[CONTENTVIEW]),
133
                   'description' => line[DESCRIPTION],
134
                   'unlimited_content_hosts' => (line[LIMIT] == 'Unlimited') ? true : false,
135
                   'max_content_hosts' => (line[LIMIT] == 'Unlimited') ? nil : line[LIMIT].to_i
136
                 }
137
        params['auto_attach'] = (line[AUTOATTACH] == 'Yes' ? true : false) if params['auto_attach']
138
        params['service_level'] = line[SERVICELEVEL].nil? || line[SERVICELEVEL].empty? ? nil : line[SERVICELEVEL]
139
        params['release_version'] = line[RELEASEVER].nil? || line[RELEASEVER].empty? ? nil : line[RELEASEVER]
140
        if !@existing[line[ORGANIZATION]].include? name
141
          print _("Creating activation key '%{name}'...") % {:name => name} if option_verbose?
142
          activationkey = @api.resource(:activation_keys).call(:create, params)
143
          @existing[line[ORGANIZATION]][activationkey['name']] = activationkey['id']
144
        else
145
          print _("Updating activation key '%{name}'...") % {:name => name} if option_verbose?
146
          params['id'] = @existing[line[ORGANIZATION]][name]
147
          activationkey = @api.resource(:activation_keys).call(:update, params)
109 148
        end
149

  
150
        update_subscriptions(activationkey, line, true)
151
        update_groups(activationkey, line)
152

  
153
        puts _('done') if option_verbose?
110 154
      end
111 155

  
112 156
      def update_groups(activationkey, line)
......
121 165
        end
122 166
      end
123 167

  
124
      def update_subscriptions(activationkey, line)
125
        if line[SUBSCRIPTIONS] && line[SUBSCRIPTIONS] != ''
126
          subscriptions = CSV.parse_line(line[SUBSCRIPTIONS], {:skip_blanks => true}).collect do |subscription_details|
127
            (amount, sku, name) = subscription_details.split('|')
128
            {
129
              :id => katello_subscription(line[ORGANIZATION], :name => name),
130
              :quantity => (amount.nil? || amount == 'Automatic') ? 0 : amount
131
            }
168
      def update_subscriptions(activationkey, line, remove_existing)
169
        existing_subscriptions = @api.resource(:subscriptions).call(:index, {
170
            'organization_id' => foreman_organization(:name => line[ORGANIZATION]),
171
            'per_page' => 999999,
172
            'activation_key_id' => activationkey['id']
173
        })['results']
174
        if remove_existing && existing_subscriptions.length > 0
175
          existing_subscriptions.map! do |existing_subscription|
176
            {:id => existing_subscription['id'], :quantity => existing_subscription['quantity_consumed']}
132 177
          end
178
          @api.resource(:activation_keys).call(:remove_subscriptions, {
179
            'id' => activationkey['id'],
180
            'subscriptions' => existing_subscriptions
181
          })
182
          existing_subscriptions = []
183
        end
133 184

  
134
          existing_subscriptions = @api.resource(:subscriptions).call(:index, {
135
              'organization_id' => foreman_organization(:name => line[ORGANIZATION]),
136
              'per_page' => 999999,
137
              'activation_key_id' => activationkey['id']
138
          })['results']
139
          if existing_subscriptions.length > 0
140
            @api.resource(:activation_keys).call(:remove_subscriptions, {
141
              'id' => activationkey['id'],
142
              'subscriptions' => existing_subscriptions
143
            })
185
        if line[Utils::Subscriptions::SUBS_NAME].nil? && line[Utils::Subscriptions::SUBS_SKU].nil?
186
          all_in_one_subscription(activationkey, existing_subscriptions, line)
187
        else
188
          single_subscription(activationkey, existing_subscriptions, line)
189
        end
190
      end
191

  
192
      def single_subscription(activationkey, existing_subscriptions, line)
193
        already_attached = false
194
        if line[Utils::Subscriptions::SUBS_SKU]
195
          already_attached = existing_subscriptions.detect do |subscription|
196
            line[Utils::Subscriptions::SUBS_SKU] == subscription['product_id']
144 197
          end
198
        elsif line[Utils::Subscriptions::SUBS_NAME]
199
          already_attached = existing_subscriptions.detect do |subscription|
200
            line[Utils::Subscriptions::SUBS_NAME] == subscription['name']
201
          end
202
        end
203
        if already_attached
204
          print _(" '%{name}' already attached...") % {:name => already_attached['name']}
205
          return
206
        end
145 207

  
146
          @api.resource(:activation_keys).call(:add_subscriptions, {
147
              'id' => activationkey['id'],
148
              'subscriptions' => subscriptions
149
          })
208
        available_subscriptions = @api.resource(:subscriptions).call(:index, {
209
                                                                       'organization_id' => activationkey['organization']['id'],
210
                                                                       'activation_key_id' => activationkey['id'],
211
                                                                       'available_for' => 'activation_key'
212
                                                                     })['results']
213

  
214
        matches = matches_by_sku_and_name([], line, available_subscriptions)
215
        matches = matches_by_type(matches, line)
216
        matches = matches_by_account(matches, line)
217
        matches = matches_by_contract(matches, line)
218
        matches = matches_by_quantity(matches, line)
219

  
220
        raise _("No matching subscriptions") if matches.empty?
221

  
222
        match = matches[0]
223
        print _(" attaching '%{name}'...") % {:name => match['name']} if option_verbose?
224

  
225
        @api.resource(:activation_keys).call(:add_subscriptions, {
226
            'id' => activationkey['id'],
227
            'subscriptions' => [match]
228
        })
229
      end
230

  
231
      def all_in_one_subscription(activationkey, existing_subscriptions, line)
232
        return if line[SUBSCRIPTIONS].nil? || line[SUBSCRIPTIONS].empty?
233

  
234
        subscriptions = CSV.parse_line(line[SUBSCRIPTIONS], {:skip_blanks => true}).collect do |details|
235
          (amount, sku, name, contract, account) = split_subscription_details(details)
236
          {
237
            :id => get_subscription(line[ORGANIZATION], :name => name),
238
            :quantity => (amount.nil? || amount == 'Automatic') ? 0 : amount.to_i
239
          }
150 240
        end
241

  
242
        @api.resource(:activation_keys).call(:add_subscriptions, {
243
                                               'id' => activationkey['id'],
244
                                               'subscriptions' => subscriptions
245
                                             })
151 246
      end
152 247

  
153 248
      def usage_limit(limit)
154 249
        Integer(limit) rescue -1
155 250
      end
251

  
252
      def shared_headers
253
        [NAME, ORGANIZATION, DESCRIPTION, LIMIT, ENVIRONMENT, CONTENTVIEW,
254
         HOSTCOLLECTIONS, AUTOATTACH, SERVICELEVEL, RELEASEVER]
255
      end
256

  
257
      def shared_columns(activationkey)
258
        name = namify(activationkey['name'])
259
        organization = activationkey['organization']['name']
260
        description = activationkey['description']
261
        limit = activationkey['unlimited_content_hosts'] ? 'Unlimited' : activationkey['max_content_hosts']
262
        environment = activationkey['environment'].nil? ? nil : activationkey['environment']['label']
263
        contentview = activationkey['content_view'].nil? ? nil : activationkey['content_view']['name']
264
        hostcollections = export_column(activationkey, 'host_collections', 'name')
265
        autoattach = activationkey['auto_attach'] ? 'Yes' : 'No'
266
        servicelevel = activationkey['service_level']
267
        releasever = activationkey['release_version']
268
        [name, organization, description, limit, environment, contentview, hostcollections,
269
         autoattach, servicelevel, releasever]
270
      end
271

  
272
      def update_existing(line)
273
        if !@existing[line[ORGANIZATION]]
274
          @existing[line[ORGANIZATION]] = {}
275
          @api.resource(:activation_keys).call(:index, {
276
              'per_page' => 999999,
277
              'organization_id' => foreman_organization(:name => line[ORGANIZATION])
278
          })['results'].each do |activationkey|
279
            @existing[line[ORGANIZATION]][activationkey['name']] = activationkey['id'] if activationkey
280
          end
281
        end
282
      end
156 283
    end
157 284
  end
158 285
end

Also available in: Unified diff