Class: TheForemanProxmox::Proxmox

Inherits:
ComputeResource
  • Object
show all
Includes:
ProxmoxComputeHelper
Defined in:
app/models/the_foreman_proxmox/proxmox.rb

Constant Summary

Constants included from ProxmoxComputeHelper

ProxmoxComputeHelper::GIGA, ProxmoxComputeHelper::KILO, ProxmoxComputeHelper::MEGA

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ProxmoxComputeHelper

#parse_cdrom, #parse_cpu, #parse_interface, #parse_interfaces, #parse_memory, #parse_vm, #parse_volume, #parse_volumes

Instance Attribute Details

#nodeObject

Returns the value of attribute node.



29
30
31
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 29

def node
  @node
end

Class Method Details

.model_nameObject



45
46
47
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 45

def self.model_name
  ComputeResource.model_name
end

.provider_friendly_nameObject



37
38
39
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 37

def self.provider_friendly_name
  "Proxmox"
end

Instance Method Details

#associated_host(vm) ⇒ Object



86
87
88
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 86

def associated_host(vm)
  associate_by('mac', vm.mac)
end

#available_imagesObject



96
97
98
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 96

def available_images
  templates.collect { |template| OpenStruct.new(id: template.vmid) }
end

#bridgesObject



90
91
92
93
94
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 90

def bridges
  node = network_client.nodes.all.first
  bridges = node.networks.all(type: 'bridge')
  bridges.sort_by(&:iface)
end

#capabilitiesObject



41
42
43
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 41

def capabilities
  [:build, :new_volume, :image]
end

#certs_to_storeObject



254
255
256
257
258
259
260
261
262
263
264
265
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 254

def certs_to_store
  return if ssl_certs.blank?
  store = OpenSSL::X509::Store.new
  ssl_certs.split(/(?=-----BEGIN)/).each do |cert|
    x509_cert = OpenSSL::X509::Certificate.new cert
    store.add_cert x509_cert
  end
  store
rescue => e
  logger.error(e)
  raise ::Foreman::Exception.new N_("Unable to store X509 certificates")
end

#connection_optionsObject



275
276
277
278
279
280
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 275

def connection_options
  opts = http_proxy ? {proxy: http_proxy.full_url} : {disable_proxy: 1}
  opts.store(:ssl_verify_peer, ssl_verify_peer)
  opts.store(:ssl_cert_store, certs_to_store) if Foreman::Cast.to_bool(ssl_verify_peer)
  opts
end

#console(uuid) ⇒ Object



282
283
284
285
286
287
288
289
290
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 282

def console(uuid)
  vm = find_vm_by_uuid(uuid)
  if vm.config.type_console == 'vnc'
    vnc_console = vm.start_console(websocket: 1)  
    WsProxy.start(:host => host, :host_port => vnc_console['port'], :password => vnc_console['ticket']).merge(:name => vm.name, :type => vm.config.type_console)
  else
    raise ::Foreman::Exception.new(N_("%s console is not supported at this time"), vm.config.type_console)
  end
end

#create_vm(args = {}) ⇒ Object



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 166

def create_vm(args = {})
  vmid = args[:vmid]
  raise ::Foreman::Exception.new N_("invalid vmid=#{vmid}") unless node.servers.id_valid?(vmid)
  image_id = args[:image_id]
  node = get_cluster_node args
  if image_id
    logger.debug("create_vm(): clone #{image_id} in #{vmid}")
    image = node.servers.get image_id
    image.clone(vmid)
  else
    logger.debug("create_vm(): #{args}")
    convert_sizes(args)
    node.servers.create(parse_vm(args))
  end
  vm = find_vm_by_uuid(vmid)
  vm
rescue => e
  logger.warn "failed to create vm: #{e}"
  destroy_vm vm.id if vm
  raise e
end

#credentials_valid?Boolean

Returns:

  • (Boolean)


49
50
51
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 49

def credentials_valid?
  errors[:url].empty? && errors[:user].empty? && errors[:user].include?('@') && errors[:password].empty? && node
end

#editable_network_interfaces?Boolean

Returns:

  • (Boolean)


213
214
215
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 213

def editable_network_interfaces?
  true
end

#find_vm_by_uuid(uuid) ⇒ Object



188
189
190
191
192
193
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 188

def find_vm_by_uuid(uuid)
  node.servers.get(uuid)
rescue Fog::Errors::Error => e
  Foreman::Logging.exception("Failed retrieving proxmox vm by vmid=#{uuid}", e)
  raise(ActiveRecord::RecordNotFound)
end

#host_compute_attrs(host) ⇒ Object



110
111
112
113
114
115
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 110

def host_compute_attrs(host)
  super.tap do |attrs|
    ostype = host.compute_attributes['config_attributes']['ostype']
    raise Foreman::Exception.new("Operating system family #{host.operatingsystem.type} is not consistent with #{ostype}") unless compute_os_types(host).include?(ostype)
  end
end

#host_interfaces_attrs(host) ⇒ Object



117
118
119
120
121
122
123
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 117

def host_interfaces_attrs(host)
  host.interfaces.select(&:physical?).each.with_index.reduce({}) do |hash, (nic, index)|
    raise ::Foreman::Exception.new N_("Identifier interface[#{index}] required.") if nic.identifier.empty?
    raise ::Foreman::Exception.new N_("Invalid identifier interface[#{index}]. Must be net[n] with n integer >= 0") unless Fog::Proxmox::ControllerHelper.valid?(Fog::Compute::Proxmox::Interface::NAME,nic.identifier)
    hash.merge(index.to_s => nic.compute_attributes.merge(id: nic.identifier, ip: nic.ip, ip6: nic.ip6))
  end
end

#image_exists?(image) ⇒ Boolean

Returns:

  • (Boolean)


221
222
223
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 221

def image_exists?(image)
  find_vm_by_uuid(image)
end

#isos(storage_id) ⇒ Object



81
82
83
84
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 81

def isos(storage_id)
  storage = node.storages.find_by_id storage_id if storage_id
  storage.volumes.list_by_content_type('iso').sort_by(&:volid) if storage
end

#new_interface(attr = {}) ⇒ Object



131
132
133
134
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 131

def new_interface(attr = {})
  opts = interface_defaults.merge(attr.to_h).deep_symbolize_keys
  Fog::Compute::Proxmox::Interface.new(opts)
end

#new_vm(attr = {}) ⇒ Object



160
161
162
163
164
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 160

def new_vm(attr = {})
  vm = node.servers.new(vm_instance_defaults.merge(parse_vm(attr)))
  logger.debug("new_vm() vm.config=#{vm.config.inspect}")
  vm
end

#new_volume(attr = {}) ⇒ Object



125
126
127
128
129
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 125

def new_volume(attr = {})     
  opts = volume_defaults('scsi',1).merge(attr.to_h).deep_symbolize_keys
  opts[:size] = opts[:size].to_s
  Fog::Compute::Proxmox::Disk.new(opts)
end

#next_vmidObject



238
239
240
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 238

def next_vmid
  node.servers.next_id
end

#nodesObject



61
62
63
64
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 61

def nodes
  nodes = client.nodes.all
  nodes.sort_by(&:node)
end

#poolsObject



66
67
68
69
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 66

def pools
  pools = identity_client.pools.all
  pools.sort_by(&:poolid)
end

#provided_attributesObject



31
32
33
34
35
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 31

def provided_attributes
  super.merge(
    :mac  => :mac
  )
end

#save_vm(uuid, attr) ⇒ Object



225
226
227
228
229
230
231
232
233
234
235
236
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 225

def save_vm(uuid, attr)
  vm = find_vm_by_uuid(uuid)
  logger.debug("save_vm(): #{attr}")
  templated = attr[:templated]
  if (templated == '1' && !vm.templated?)
    vm.template
  else
    merged = vm.config.attributes.merge!(parse_vm(attr).symbolize_keys).deep_symbolize_keys
    filtered = merged.reject { |key,value| %w[node vmid].include?(key) || [:templated,:image_id].include?(key) || value.to_s.empty? }
    vm.update(filtered)
  end
end

#set_vm_interfaces_attributes(vm, vm_attrs) ⇒ Object



152
153
154
155
156
157
158
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 152

def set_vm_interfaces_attributes(vm, vm_attrs)
  if vm.config.respond_to?(:interfaces)
    interfaces = vm.config.interfaces || []
    vm_attrs[:interfaces_attributes] = Hash[interfaces.each_with_index.map { |interface, idx| [idx.to_s, interface.attributes] }]
  end
  vm_attrs
end

#set_vm_volumes_attributes(vm, vm_attrs) ⇒ Object



144
145
146
147
148
149
150
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 144

def set_vm_volumes_attributes(vm, vm_attrs)
  if vm.config.respond_to?(:volumes)
    volumes = vm.config.volumes || []
    vm_attrs[:volumes_attributes] = Hash[volumes.each_with_index.map { |volume, idx| [idx.to_s, volume.attributes] }]
  end
  vm_attrs
end

#ssl_certsObject



246
247
248
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 246

def ssl_certs  
  self.attrs[:ssl_certs]
end

#ssl_certs=(value) ⇒ Object



250
251
252
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 250

def ssl_certs=(value)
  self.attrs[:ssl_certs] = value
end

#ssl_verify_peerObject



267
268
269
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 267

def ssl_verify_peer
  self.attrs[:ssl_verify_peer].blank? ? false : Foreman::Cast.to_bool(self.attrs[:ssl_verify_peer])
end

#ssl_verify_peer=(value) ⇒ Object



271
272
273
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 271

def ssl_verify_peer=(value)
  self.attrs[:ssl_verify_peer] = value
end

#storagesObject



71
72
73
74
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 71

def storages
  storages = node.storages.list_by_content_type 'images'
  storages.sort_by(&:storage)
end

#storages_isosObject



76
77
78
79
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 76

def storages_isos
  storages = node.storages.list_by_content_type 'iso'
  storages.sort_by(&:storage)
end

#supports_update?Boolean

Returns:

  • (Boolean)


195
196
197
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 195

def supports_update?
  true
end

#template(vmid) ⇒ Object



106
107
108
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 106

def template(vmid)
  find_vm_by_uuid(vmid)
end

#templatesObject



100
101
102
103
104
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 100

def templates
  storage = storages.first
  images = storage.volumes.list_by_content_type('images')
  images.select { |image| image.templated? }
end

#test_connection(options = {}) ⇒ Object



53
54
55
56
57
58
59
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 53

def test_connection(options = {})
  super
  credentials_valid?
rescue => e
  errors[:base] << e.message
  errors[:url] << e.message
end

#update_required?(old_attrs, new_attrs) ⇒ Boolean

Returns:

  • (Boolean)


199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 199

def update_required?(old_attrs, new_attrs)
  return true if super(old_attrs, new_attrs)

  new_attrs[:interfaces_attributes].each do |key, interface|
    return true if (interface[:id].blank? || interface[:_delete] == '1') && key != 'new_interfaces' #ignore the template
  end if new_attrs[:interfaces_attributes]

  new_attrs[:volumes_attributes].each do |key, volume|
    return true if (volume[:id].blank? || volume[:_delete] == '1') && key != 'new_volumes' #ignore the template
  end if new_attrs[:volumes_attributes]

  false
end

#user_data_supported?Boolean

Returns:

  • (Boolean)


217
218
219
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 217

def user_data_supported?
  true
end

#vm_compute_attributes(vm) ⇒ Object



136
137
138
139
140
141
142
# File 'app/models/the_foreman_proxmox/proxmox.rb', line 136

def vm_compute_attributes(vm)
  vm_attrs = vm.attributes rescue {}
  vm_attrs = vm_attrs.reject{|k,v| k == :id }  
  vm_attrs = set_vm_volumes_attributes(vm, vm_attrs)
  vm_attrs = set_vm_interfaces_attributes(vm, vm_attrs)
  vm_attrs
end