Class: Chef::Knife::EcKeyImport

Inherits:
Chef::Knife show all
Includes:
EcKeyBase
Defined in:
lib/chef/knife/ec_key_import.rb

Instance Method Summary collapse

Methods included from EcKeyBase

#db, included, #load_config_from_file!, #sql_password, #veil, #veil_config

Instance Method Details

#import_key_data(path) ⇒ Object


68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/chef/knife/ec_key_import.rb', line 68

def import_key_data(path)
  key_data = JSON.parse(File.read(path))
  key_data.each do |d|
    case d['type']
    when 'client'
      next if config[:users_only]
      insert_key_data_for_client(d)
    when 'user'
      next if config[:clients_only]
      insert_key_data_for_user(d)
    else
      ui.warn "Unkown actor type #{d['type']} for #{d['name']}"
      next
    end
  end
end

#import_user_data(path) ⇒ Object


166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/chef/knife/ec_key_import.rb', line 166

def import_user_data(path)
  key_data = JSON.parse(File.read(path))
  knife_ec_error_handler = config[:knife_ec_error_handler]
  key_data.each do |d|
    if d['username'] == 'pivotal' && config[:skip_pivotal]
      ui.warn "Skipping pivotal user."
      next
    end

    ui.msg "Updating user record for #{d['username']}"
    users_to_update = db[:users].where(:username => d['username'])

    if users_to_update.count != 1
      ui.warn "Wrong number of users to update for #{d['username']}. Skipping"
    else
      # Remove authz id from import since this will no longer
      # be valid.
      d.delete('authz_id')
      d.delete('id') if config[:skip_ids]
      # If the hash_type in the export,
      # we are dealing with a record where the password is still in the
      # serialized_obejct.  Explictly setting these to nil ensures that the
      # password set in the restore is wiped out.
      unless d.has_key?('hash_type')
        d['hash_type'] = nil
        d['hashed_password'] = nil
        d['salt'] = nil
      end
      begin
        users_to_update.update(d)
      rescue => ex
        ui.warn "Could not restore user #{d['username']}"
        if ex.class == Sequel::ForeignKeyConstraintViolation
          message = "This error usually indicates that a user already exists with a different ID and is associated with one or more organizations on the target system.  The username is #{d['username']} and the ID in the backup files is #{d['id']}"
          ui.warn message
          ex = ex.exception "#{ex.message} #{message}"
        end
        knife_ec_error_handler.add(ex) if knife_ec_error_handler
      end
    end
  end
end

#insert_key_data_for_client(d) ⇒ Object

If a given key_name already exists for the client, update it, otherwise insert a new key into the key table.

Unlike users, we never want to keep the internal ID from the backup.

The org_id is likely different than that stored in the backup. We query the new org_id based on org_name, caching it to avoid multiple lookups in a large org.


94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/chef/knife/ec_key_import.rb', line 94

def insert_key_data_for_client(d)
  ui.msg "Updating key data for client[#{d['name']}]"

  org_id = @org_id_cache.fetch(d['org_name'])
  if org_id.nil?
    ui.warn "Could not find organization for client[#{d['name']}], skipping."
    ui.warn "Organizations much be restored before key data can be imported."
    return
  end

  existing_client = db[:clients].where(:org_id => org_id, :name => d['name']).first
  if existing_client.nil?
    ui.warn "Did not find existing client record for #{d['name']}, skipping."
    ui.warn "Client records must be restored before key data can be imported."
    return
  end

  new_id = existing_client[:id]
  Chef::Log.debug("Found client id for #{d['name']}: #{new_id}")
  upsert_key_record(key_record_for_db(d, new_id))
end

#insert_key_data_for_user(d) ⇒ Object

Insert key data for each user record

When :skip_id's is set, we are not using the ids from the backup. In this case, look up the user id in the users table.

When :skip_id's is not set, we are using the ids from the backup. The update_key trigger on the users table should ensure that the user ids have already been replaced and should match what we have in the backup.


125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/chef/knife/ec_key_import.rb', line 125

def insert_key_data_for_user(d)
  if d['name'] == 'pivotal' && config[:skip_pivotal]
    ui.warn "Skipping pivotal user."
    return
  end
  ui.msg "Updating key data for user[#{d['name']}]"
  new_id = if config[:skip_ids]
             db[:users].where(:username => d['name']).first[:id]
           else
             d['id']
           end
  Chef::Log.debug("Found user id for #{d['name']}: #{new_id}")
  upsert_key_record(key_record_for_db(d, new_id))
end

#key_record_for_db(d, new_id = nil) ⇒ Object


155
156
157
158
159
160
161
162
163
164
# File 'lib/chef/knife/ec_key_import.rb', line 155

def key_record_for_db(d, new_id=nil)
  {
    :id => new_id || d['id'],
    :key_name => d['key_name'],
    :public_key => d['public_key'],
    :key_version => d['key_version'],
    :created_at => Time.now,
    :expires_at => d['expires_at']
  }
end

#runObject


53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/chef/knife/ec_key_import.rb', line 53

def run
  if config[:sql_user].nil? || config[:sql_password].nil?
    load_config_from_file!
  end

  @org_id_cache = Chef::OrgIdCache.new(db)

  # user_data_path defaults to key_dump.json to support
  # older knife-ec-backup exports
  user_data_path = @name_args[0] || "key_dump.json"
  key_data_path = @name_args[1] || "key_table_dump.json"
  import_user_data(user_data_path) unless (config[:skip_users_table] || config[:clients_only])
  import_key_data(key_data_path) unless config[:skip_keys_table]
end

#upsert_key_record(r) ⇒ Object


140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/chef/knife/ec_key_import.rb', line 140

def upsert_key_record(r)
  key_records_to_update = db[:keys].where(:key_name => r[:key_name], :id => r[:id])
  case key_records_to_update.count
  when 0
    Chef::Log.debug("No existing records found for #{r[:key_name]}, #{r[:id]}")
    db[:keys].insert(r)
  when 1
    Chef::Log.debug("1 record found for #{r[:key_name]}, #{r[:id]}")
    key_records_to_update.update(r)
  else
    ui.warn "Found too many records for actor id #{r[:id]} key #{d[:key_name]}"
    return
  end
end