Project

General

Profile

Revision c4dbc7a3

Added by Thomas McKay over 7 years ago

updates to tests and functionality

+ added export containers
+ export content-view-filters erratum and rpm types
+ 'hammer csv import' now works from --dir https://somewhere
+ 'hammer csv import' tests and fixes

View differences:

lib/hammer_cli_csv.rb
13 13
  require 'hammer_cli_csv/architectures'
14 14
  require 'hammer_cli_csv/compute_profiles'
15 15
  require 'hammer_cli_csv/compute_resources'
16
  require 'hammer_cli_csv/containers'
16 17
  require 'hammer_cli_csv/content_hosts'
17 18
  require 'hammer_cli_csv/content_views'
18 19
  require 'hammer_cli_csv/content_view_filters'
lib/hammer_cli_csv/base.rb
27 27
    COUNT = 'Count'
28 28

  
29 29
    def execute
30
      @server = HammerCLI::Settings.settings[:_params][:host] ||
30
      @server = (HammerCLI::Settings.settings[:_params] &&
31
                 HammerCLI::Settings.settings[:_params][:host]) ||
31 32
        HammerCLI::Settings.get(:csv, :host) ||
32 33
        HammerCLI::Settings.get(:katello, :host) ||
33 34
        HammerCLI::Settings.get(:foreman, :host)
34
      @username = HammerCLI::Settings.settings[:_params][:username] ||
35
      @username = (HammerCLI::Settings.settings[:_params] &&
36
                   HammerCLI::Settings.settings[:_params][:username]) ||
35 37
        HammerCLI::Settings.get(:csv, :username) ||
36 38
        HammerCLI::Settings.get(:katello, :username) ||
37 39
        HammerCLI::Settings.get(:foreman, :username)
38
      @password = HammerCLI::Settings.settings[:_params][:password] ||
40
      @password = (HammerCLI::Settings.settings[:_params] &&
41
                   HammerCLI::Settings.settings[:_params][:password]) ||
39 42
        HammerCLI::Settings.get(:csv, :password) ||
40 43
        HammerCLI::Settings.get(:katello, :password) ||
41 44
        HammerCLI::Settings.get(:foreman, :password)
......
714 717
      result
715 718
    end
716 719

  
720
    def foreman_container(options = {})
721
      @containers ||= {}
722

  
723
      if options[:name]
724
        return nil if options[:name].nil? || options[:name].empty?
725
        options[:id] = @containers[options[:name]]
726
        if !options[:id]
727
          container = @api.resource(:containers).call(:index, {
728
                                                       :per_page => 999999,
729
                                                       'search' => "name=\"#{options[:name]}\""
730
                                                     })['results']
731
          raise "Container '#{options[:name]}' not found" if !container || container.empty?
732
          options[:id] = container[0]['id']
733
          @containers[options[:name]] = options[:id]
734
        end
735
        result = options[:id]
736
      else
737
        return nil if options[:id].nil?
738
        options[:name] = @containers.key(options[:id])
739
        if !options[:name]
740
          container = @api.resource(:containers).call(:show, {'id' => options[:id]})
741
          raise "Container 'id=#{options[:id]}' not found" if !container || container.empty?
742
          options[:name] = container['name']
743
          @containers[options[:name]] = options[:id]
744
        end
745
        result = options[:name]
746
      end
747

  
748
      result
749
    end
750

  
751

  
717 752
    def build_os_name(name, major, minor)
718 753
      name += " #{major}" if major && major != ''
719 754
      name += ".#{minor}" if minor && minor != ''
lib/hammer_cli_csv/containers.rb
1
module HammerCLICsv
2
  class CsvCommand
3
    class ContainersCommand < BaseCommand
4
      command_name 'containers'
5
      desc         'import or export containers'
6

  
7
      REGISTRY = 'Registry'
8
      REPOSITORY = 'Repository:Tag'
9
      COMPUTERESOURCE = 'Compute Resource'
10
      ATTACH = 'Attach I/O'
11
      ENTRYPOINT = 'Entry Point'
12
      COMMAND = 'Command'
13

  
14
      def export
15
        CSV.open(option_file || '/dev/stdout', 'wb') do |csv|
16
          csv << [NAME, COUNT, REGISTRY, REPOSITORY, COMPUTERESOURCE, ATTACH, ENTRYPOINT, COMMAND]
17
          @api.resource(:containers).call(:index, {'per_page' => 999999})['results'].each do |container|
18
            csv << [container['name'], 1,
19
                    container['registry_name'],
20
                    "#{container['repository_name']}:#{container['tag']}",
21
                    container['compute_resource_name'],
22
                    export_attach_types(container),
23
                    container['entrypoint'],
24
                    container['command']]
25
          end
26
        end
27
      end
28

  
29
      def import
30
        @existing = {}
31

  
32
        thread_import do |line|
33
          create_containers_from_csv(line)
34
        end
35
      end
36

  
37
      def create_containers_from_csv(line)
38
        # TODO: containers cannot be updated (no api)
39
        # line[COUNT].to_i.times do |number|
40
        #   name = namify(line[NAME], number)
41
        #   params =  { 'id' => foreman_container(:name => name),
42
        #               'container' => {
43
        #                 'name' => name,
44
        #                 'command' => line[COMMAND]
45
        #               }
46
        #             }
47
        #   print "Updating container '#{name}'..." if option_verbose?
48
        #   @api.resource(:containers).call(:update, params)
49
        # end
50
        # print "done\n" if option_verbose?
51
      end
52

  
53
      private
54

  
55
      def export_attach_types(container)
56
        types = []
57
        types << 'tty' if container['tty']
58
        types << 'stdin' if container['attach_stdin']
59
        types << 'stdout' if container['attach_stdout']
60
        types << 'stderr' if container['attach_stderr']
61
        types.join(',')
62
      end
63
    end
64
  end
65
end
lib/hammer_cli_csv/content_hosts.rb
172 172
                'guest_ids' => guest_ids
173 173
            })
174 174
          end
175
          puts _('done') if option_verbose?
175 176
        end
176
        puts _('done') if option_verbose?
177 177
      end
178 178

  
179 179
      def create_content_hosts_from_csv(line)
lib/hammer_cli_csv/content_view_filters.rb
22 22
          })['results'].each do |organization|
23 23
            next if option_organization && organization['name'] != option_organization
24 24

  
25
            composite_contentviews = []
26 25
            @api.resource(:content_views).call(:index, {
27 26
                'per_page' => 999999,
28 27
                'organization_id' => organization['id'],
......
31 30
              @api.resource(:content_view_filters).call(:index, {
32 31
                  'content_view_id' => contentview['id']
33 32
              })['results'].collect do |filter|
34
                filter_type = "#{filter['inclusion'] == true ? 'Include' : 'Exclude'} #{filter['type']}"
33
                filter_type = "#{filter['inclusion'] == true ? 'Include' : 'Exclude'} #{export_filter_type(filter['type'])}"
35 34

  
35
                rules = nil
36 36
                case filter['type']
37 37
                when /rpm/
38
                  rules = CSV.generate do |column|
39
                    column << filter['rules'].collect do |rule|
40
                      if rule['version']
41
                        "#{rule['name']}|=|#{rule['version']}"
42
                      elsif rule['min_version'] && rule['max_version']
43
                        "#{rule['name']}|-|#{rule['min_version']},#{rule['max_version']}"
44
                      elsif rule['min_version']
45
                        "#{rule['name']}|>|#{rule['min_version']}"
46
                      elsif rule['max_version']
47
                        "#{rule['name']}|<|#{rule['max_version']}"
48
                      end
49
                    end
50
                  end
51
                  rules.delete!("\n")
38
                  rules = export_rpm_rules(filter)
52 39
                when /erratum/
53
                  rules = CSV.generate do |column|
54
                    rule = filter['rules'][0]
55
                    conditions = []
56
                    conditions << "start = #{DateTime.parse(rule['start_date']).strftime('%F')}" if rule['start_date']
57
                    conditions << "end = #{DateTime.parse(rule['end_date']).strftime('%F')}" if rule['end_date']
58
                    conditions += rule['types']
59
                    column << conditions
60
                  end
61
                  rules.delete!("\n")
40
                  rules = export_erratum_rules(filter)
62 41
                when /package_group/
42
                  rules = export_package_group_rules(filter)
63 43
                else
64 44
                  raise "Unknown filter rule type '#{filter['type']}'"
65 45
                end
66 46

  
67
                name = contentview['name']
47
                name = filter['name']
68 48
                repositories = export_column(filter, 'repositories', 'name')
69 49
                csv << [name, 1, contentview['name'], organization['name'], filter_type, filter['description'],
70 50
                        repositories, rules]
......
82 62
        end
83 63
      end
84 64

  
65
      # rubocop:disable CyclomaticComplexity
85 66
      def create_filters_from_csv(line)
86 67
        return if option_organization && line[ORGANIZATION] != option_organization
87 68

  
......
101 82
        end
102 83

  
103 84
        line[COUNT].to_i.times do |number|
104
          name = namify(line[NAME], number)
85
          filter_name = namify(line[NAME], number)
105 86

  
106
          filter_id = @existing_filters[line[ORGANIZATION]][line[CONTENTVIEW]][name]
87
          filter_id = @existing_filters[line[ORGANIZATION]][line[CONTENTVIEW]][filter_name]
88
          filter_type = import_filter_type(line[TYPE])
107 89
          if !filter_id
108
            print "Creating filter '#{name}' for content view filter '#{line[CONTENTVIEW]}'..." if option_verbose?
90
            print "Creating filter '#{filter_name}' for content view filter '#{line[CONTENTVIEW]}'..." if option_verbose?
109 91
            filter_id = @api.resource(:content_view_filters).call(:create, {
110 92
                'content_view_id' => katello_contentview(line[ORGANIZATION], :name => line[CONTENTVIEW]),
111
                'name' => name,
93
                'name' => filter_name,
112 94
                'description' => line[DESCRIPTION],
113
                'type' => filter_type(line[TYPE]),
95
                'type' => filter_type,
114 96
                'inclusion' => filter_inclusion?(line[TYPE]),
115 97
                'repository_ids' => repository_ids
116 98
            })['id']
117
            @existing_filters[line[ORGANIZATION]][name] = filter_id
99
            @existing_filters[line[ORGANIZATION]][filter_name] = filter_id
118 100
          else
119
            print "Updating filter '#{name}' for content view filter '#{line[CONTENTVIEW]}'..." if option_verbose?
101
            print "Updating filter '#{filter_name}' for content view filter '#{line[CONTENTVIEW]}'..." if option_verbose?
120 102
            @api.resource(:content_view_filters).call(:update, {
121 103
                'id' => filter_id,
122 104
                'description' => line[DESCRIPTION],
123
                'type' => filter_type(line[TYPE]),
105
                'type' => filter_type,
124 106
                'inclusion' => filter_inclusion?(line[TYPE]),
125 107
                'repository_ids' => repository_ids
126 108
            })
127 109
          end
128 110

  
129
          @existing_rules ||= {}
130
          @existing_rules[line[ORGANIZATION]] ||= {}
131
          @existing_rules[line[ORGANIZATION]][line[CONTENTVIEW]] ||= {}
111
          existing_rules = {}
132 112
          @api.resource(:content_view_filter_rules).call(:index, {
133 113
              'per_page' => 999999,
134 114
              'content_view_filter_id' => filter_id
135 115
          })['results'].each do |rule|
136
            @existing_rules[line[ORGANIZATION]][line[CONTENTVIEW]][rule['name']] = rule
116
            existing_rules[rule['name']] = rule
137 117
          end
138 118

  
139 119
          collect_column(line[RULES]) do |rule|
......
142 122
              'content_view_filter_id' => filter_id,
143 123
              'name' => name
144 124
            }
145
            if type == '='
146
              params['type'] = 'equal',
147
                               params['version'] = version
125
            if type == 'all'
126
              # empty
127
            elsif type == '='
128
              params['version'] = version
148 129
            elsif type == '<'
149
              params['type'] = 'less',
150
                               params['max_version'] = version
130
              params['max_version'] = version
151 131
            elsif type == '>'
152
              params['type'] = 'greater',
153
                               params['min_version'] = version
132
              params['min_version'] = version
154 133
            elsif type == '-'
155
              params['type'] = 'range',
156
                               min_version, max_version = version.split(',')
134
              min_version, max_version = version.split(',')
157 135
              params['min_version'] = min_version
158 136
              params['max_version'] = max_version
137
            elsif filter_type == 'package_group'
138
              params['uuid'] = name # TODO: this is not right
159 139
            else
160 140
              raise "Unknown type '#{type}' from '#{line[RULES]}'"
161 141
            end
162 142

  
163
            rule = @existing_rules[line[ORGANIZATION]][line[CONTENTVIEW]][name]
143
            rule = existing_rules[name]
164 144
            if !rule
165 145
              print "." if option_verbose?
166 146
              rule = @api.resource(:content_view_filter_rules).call(:create, params)
167
              @existing_rules[line[ORGANIZATION]][line[CONTENTVIEW]][rule['name']] = rule
147
              existing_rules[rule['name']] = rule
168 148
            else
169 149
              print "." if option_verbose?
170 150
              params['id'] = rule['id']
......
181 161

  
182 162
      private
183 163

  
184
      def filter_type(type)
185
        if type.split[1] == 'RPM'
164
      def import_filter_type(type)
165
        case type.split[1..-1].join(' ')
166
        when /packages/i
186 167
          'rpm'
168
        when /package groups/i
169
          'package_group'
170
        else
171
          'unknown'
172
        end
173
      end
174

  
175
      def export_filter_type(type)
176
        case type.split[1]
177
        when /rpm/i
178
          'Packages'
179
        when /package_group/i
180
          'Package Groups'
187 181
        else
188 182
          'unknown'
189 183
        end
......
196 190
          false
197 191
        end
198 192
      end
193

  
194
      def export_rpm_rules(filter)
195
        rules = CSV.generate do |column|
196
          column << filter['rules'].collect do |rule|
197
            if rule['version']
198
              "#{rule['name']}|=|#{rule['version']}"
199
            elsif rule['min_version'] && rule['max_version']
200
              "#{rule['name']}|-|#{rule['min_version']},#{rule['max_version']}"
201
            elsif rule['min_version']
202
              "#{rule['name']}|>|#{rule['min_version']}"
203
            elsif rule['max_version']
204
              "#{rule['name']}|<|#{rule['max_version']}"
205
            else
206
              "#{rule['name']}|all"
207
            end
208
          end
209
        end
210
        rules.delete!("\n")
211
      end
212

  
213
      def export_erratum_rules(filter)
214
        rules = CSV.generate do |column|
215
          rule = filter['rules'][0]
216
          conditions = []
217
          conditions << "start = #{DateTime.parse(rule['start_date']).strftime('%F')}" if rule['start_date']
218
          conditions << "end = #{DateTime.parse(rule['end_date']).strftime('%F')}" if rule['end_date']
219
          conditions << "types = #{rule['types'].join(',')}" if rule['types']
220
          conditions << "errata = #{rule['errata_id']}" if rule['errata_id']
221
          column << conditions
222
        end
223
        rules.delete!("\n")
224
      end
225

  
226
      def export_package_group_rules(filter)
227
        rules = CSV.generate do |column|
228
          column << filter['rules'].collect do |rule|
229
            rule['name']
230
          end
231
        end
232
        rules.delete!("\n")
233
      end
199 234
    end
200 235
  end
201 236
end
lib/hammer_cli_csv/import.rb
1
require 'open-uri'
2

  
1 3
module HammerCLICsv
2 4
  class CsvCommand
3 5
    class ImportCommand < HammerCLI::Apipie::Command
4 6
      command_name 'import'
5 7
      desc         'import by directory'
6 8

  
7
      option %w(-v --verbose), :flag, 'be verbose'
8
      option %w(--threads), 'THREAD_COUNT', 'Number of threads to hammer with', :default => 1
9
      option '--dir', 'DIRECTORY', 'directory to import from'
9
      option %w(-v --verbose), :flag, _('be verbose')
10
      option %w(--threads), 'THREAD_COUNT', _('Number of threads to hammer with'), :default => 1
11
      option '--dir', 'DIRECTORY', _('directory to import from')
12
      option %w(--organization), 'ORGANIZATION', _('Only process organization matching this name')
13
      option %w(--prefix), 'PREFIX', _('Prefix for all name columns')
10 14

  
11
      RESOURCES = %w( organizations locations puppet_environments operating_systems
15
      RESOURCES = %w( settings organizations locations puppet_environments operating_systems
12 16
                      domains architectures partition_tables lifecycle_environments host_collections
13 17
                      provisioning_templates
14 18
                      subscriptions products content_views content_view_filters activation_keys
......
19 23
      end
20 24

  
21 25
      def execute
22
        @api = ApipieBindings::API.new({:uri => get_option(:host), :username => get_option(:username),
23
                                        :password => get_option(:password), :api_version => 2})
26
        @server = (HammerCLI::Settings.settings[:_params] &&
27
                   HammerCLI::Settings.settings[:_params][:host]) ||
28
          HammerCLI::Settings.get(:csv, :host) ||
29
          HammerCLI::Settings.get(:katello, :host) ||
30
          HammerCLI::Settings.get(:foreman, :host)
31
        @username = (HammerCLI::Settings.settings[:_params] &&
32
                     HammerCLI::Settings.settings[:_params][:username]) ||
33
          HammerCLI::Settings.get(:csv, :username) ||
34
          HammerCLI::Settings.get(:katello, :username) ||
35
          HammerCLI::Settings.get(:foreman, :username)
36
        @password = (HammerCLI::Settings.settings[:_params] &&
37
                     HammerCLI::Settings.settings[:_params][:password]) ||
38
          HammerCLI::Settings.get(:csv, :password) ||
39
          HammerCLI::Settings.get(:katello, :password) ||
40
          HammerCLI::Settings.get(:foreman, :password)
41
        @api = ApipieBindings::API.new({:uri => @server, :username => @username,
42
                                        :password => @password, :api_version => 2})
24 43

  
25 44
        # Swing the hammers
26 45
        RESOURCES.each do |resource|
......
43 62
      def hammer_resource(resource)
44 63
        return if !self.send("option_#{resource}") && !option_dir
45 64
        options_file = self.send("option_#{resource}") || "#{option_dir}/#{resource.sub('_', '-')}.csv"
46
        if !File.exists? options_file
47
          return if option_dir
65
        unless options_file_exists? options_file
66
          if option_dir
67
            puts _("Skipping #{resource} because '#{options_file}' does not exist") if option_verbose?
68
            return
69
          end
48 70
          raise "File for #{resource} '#{options_file}' does not exist"
49 71
        end
72
        puts _("Importing #{resource} from '#{options_file}'") if option_verbose?
50 73

  
51 74
        args = %W( csv #{resource.sub('_', '-')} --file #{options_file} )
52 75
        args << '-v' if option_verbose?
76
        args += %W( --organization #{option_organization} ) if option_organization
77
        args += %W( --prefix #{option_prefix} ) if option_prefix
53 78
        args += %W( --threads #{option_threads} )
54 79
        hammer.run(args)
55 80
      end
56 81

  
57 82
      private
58 83

  
84
      def options_file_exists?(options_file)
85
        f = open(options_file)
86
        f.close
87
        true
88
      rescue
89
        false
90
      end
91

  
59 92
      def get_option(name)
60 93
        HammerCLI::Settings.settings[:_params][name] ||
61 94
          HammerCLI::Settings.get(:csv, name) ||
lib/hammer_cli_csv/organizations.rb
37 37
      end
38 38

  
39 39
      def create_organizations_from_csv(line)
40
        return if option_organization && line[ORGANIZATION] != option_organization
41

  
42 40
        line[COUNT].to_i.times do |number|
43 41
          name = namify(line[NAME], number)
42
          return if option_organization && name != option_organization
44 43
          label = namify(line[LABEL], number)
45 44
          if !@existing.include? name
46 45
            print "Creating organization '#{name}'... " if option_verbose?
test/data/settings.csv
1 1
Name,Count,Value
2 2
administrator,1,root@example.com
3 3
idle_timeout,1,60000
4
remote_execution_global_proxy,1,true
5
require_ssl_smart_proxies,1,false
test/import_test.rb
1
require File.join(File.dirname(__FILE__), 'csv_test_helper')
2

  
3
require 'stringio'
4
require 'tempfile'
5

  
6
describe 'users' do
7
  extend CommandTestHelper
8

  
9
  before :each do
10
    HammerCLI::Settings.load_from_file 'test/config.yml'
11
  end
12

  
13
  context "--dir" do
14
    it "hammer csv import --verbose --dir does-not-exist" do
15
      stdout,stderr = capture {
16
        hammer.run(%W{--debug csv import --verbose --dir does-not-exist})
17
      }
18
      stderr.must_equal ''
19
      stdout.must_equal(
20
<<-eos
21
Skipping settings because 'does-not-exist/settings.csv' does not exist
22
Skipping organizations because 'does-not-exist/organizations.csv' does not exist
23
Skipping locations because 'does-not-exist/locations.csv' does not exist
24
Skipping puppet_environments because 'does-not-exist/puppet-environments.csv' does not exist
25
Skipping operating_systems because 'does-not-exist/operating-systems.csv' does not exist
26
Skipping domains because 'does-not-exist/domains.csv' does not exist
27
Skipping architectures because 'does-not-exist/architectures.csv' does not exist
28
Skipping partition_tables because 'does-not-exist/partition-tables.csv' does not exist
29
Skipping lifecycle_environments because 'does-not-exist/lifecycle-environments.csv' does not exist
30
Skipping host_collections because 'does-not-exist/host-collections.csv' does not exist
31
Skipping provisioning_templates because 'does-not-exist/provisioning-templates.csv' does not exist
32
Skipping subscriptions because 'does-not-exist/subscriptions.csv' does not exist
33
Skipping products because 'does-not-exist/products.csv' does not exist
34
Skipping content_views because 'does-not-exist/content-views.csv' does not exist
35
Skipping content_view_filters because 'does-not-exist/content-view_filters.csv' does not exist
36
Skipping activation_keys because 'does-not-exist/activation-keys.csv' does not exist
37
Skipping hosts because 'does-not-exist/hosts.csv' does not exist
38
Skipping content_hosts because 'does-not-exist/content-hosts.csv' does not exist
39
Skipping reports because 'does-not-exist/reports.csv' does not exist
40
Skipping roles because 'does-not-exist/roles.csv' does not exist
41
Skipping users because 'does-not-exist/users.csv' does not exist
42
eos
43
)
44
    end
45

  
46
    it "hammer csv import --verbose --organizations does-not-exist.csv" do
47
      stdout,stderr = capture {
48
        hammer.run(%W{csv import --verbose --organizations does-not-exist.csv})
49
      }
50
      stdout.must_equal ''
51
      stderr[0..-2].must_equal 'Error: File for organizations \'does-not-exist.csv\' does not exist'
52
    end
53

  
54
    it "hammer csv import --verbose --organization unknown-org --organizations test/data/organizations.csv" do
55
      stdout,stderr = capture {
56
        hammer.run(%W{csv import --verbose --organization unknown-org --organizations test/data/organizations.csv})
57
      }
58
      stderr.must_equal ''
59
      stdout[0..-2].must_equal 'Importing organizations from \'test/data/organizations.csv\''
60
    end
61

  
62
    it "hammer csv import --verbose --organization unknown-org --organizations test/data/organizations.csv" do
63
      stdout,stderr = capture {
64
        hammer.run(%W{csv import --verbose --organization unknown-org --organizations test/data/organizations.csv})
65
      }
66
      stderr.must_equal ''
67
      stdout[0..-2].must_equal 'Importing organizations from \'test/data/organizations.csv\''
68
    end
69

  
70
    it "hammer csv import --verbose --prefix $rand --organizations test/data/organizations.csv" do
71
      prefix = rand(10000)
72
      stdout,stderr = capture {
73
        hammer.run(%W{csv import --verbose --prefix #{prefix} --organizations test/data/organizations.csv})
74
      }
75
      stderr.must_equal ''
76
      stdout[0..-2].must_equal "Importing organizations from 'test/data/organizations.csv'\nCreating organization '#{prefix}Mega Corporation'... done"
77
    end
78
  end
79
end

Also available in: Unified diff