Project

General

Profile

« Previous | Next » 

Revision fba2bf5f

Added by Greg Sutcliffe over 10 years ago

Fixes #3927 - Allow VMs to provision via user-data

View differences:

app/assets/javascripts/application.js
}
function template_info(div, url) {
os_id = $("#host_operatingsystem_id :selected").attr("value");
env_id = $("#host_environment_id :selected").attr("value");
hostgroup_id = $("#host_hostgroup_id :selected").attr("value");
form = $("form").serialize();
build = $('input:radio[name$="[provision_method]"]:checked').val();
$(div).html(spinner_placeholder());
$(div).load(url + "?operatingsystem_id=" + os_id + "&hostgroup_id=" + hostgroup_id + "&environment_id=" + env_id+"&provisioning="+build,
$(div).load(url + "?provisioning=" + build + "&" + form,
function(response, status, xhr) {
if (status == "error") {
$(div).html('<div class="alert alert-warning alert-dismissable">' +
app/controllers/hosts_controller.rb
render :partial => 'form'
end
def template_used
kinds = params[:provisioning] == 'image' ? [TemplateKind.find_by_name('finish')] : TemplateKind.all
host = params[:host]
kinds = if params[:provisioning] == 'image'
cr = ComputeResource.find_by_id(host[:compute_resource_id])
images = cr.try(:images)
if images.nil?
[TemplateKind.find_by_name('finish')]
else
uuid = host[:compute_attributes][cr.image_param_name]
image_kind = images.find_by_uuid(uuid).try(:user_data) ? 'user_data' : 'finish'
[TemplateKind.find_by_name(image_kind)]
end
else
TemplateKind.all
end
templates = kinds.map do |kind|
ConfigTemplate.find_template({:kind => kind.name, :operatingsystem_id => params[:operatingsystem_id],
:hostgroup_id => params[:hostgroup_id], :environment_id => params[:environment_id]})
ConfigTemplate.find_template({:kind => kind.name,
:operatingsystem_id => host[:operatingsystem_id],
:hostgroup_id => host[:hostgroup_id],
:environment_id => host[:environment_id]
})
end.compact
return not_found if templates.empty?
render :partial => "provisioning", :locals => {:templates => templates}
app/models/compute_resource.rb
list[PROVIDERS.index(provider)] rescue ""
end
def image_param_name
:image_id
end
# returns a new fog server instance
def new_vm attr={}
test_connection
app/models/compute_resources/foreman/model/openstack.rb
ComputeResource.model_name
end
def image_param_name
:image_ref
end
def capabilities
[:image]
end
app/models/concerns/orchestration/compute.rb
end
def compute?
compute_resource_id.present? and compute_attributes.present?
compute_resource_id.present? && ( compute_attributes.present? || uuid.present? )
end
def compute_object
......
end
def queue_compute_create
queue.create(:name => _("Set up compute instance %s") % self, :priority => 1,
queue.create(:name => _("Render user data template for %s") % self, :priority => 1,
:action => [self, :setUserData]) if find_image.try(:user_data)
queue.create(:name => _("Set up compute instance %s") % self, :priority => 2,
:action => [self, :setCompute])
queue.create(:name => _("Acquire IP address for %s") % self, :priority => 2,
queue.create(:name => _("Acquire IP address for %s") % self, :priority => 3,
:action => [self, :setComputeIP]) if compute_resource.provided_attributes.keys.include?(:ip)
queue.create(:name => _("Query instance details for %s") % self, :priority => 3,
queue.create(:name => _("Query instance details for %s") % self, :priority => 4,
:action => [self, :setComputeDetails])
queue.create(:name => _("Power up compute instance %s") % self, :priority => 1000,
:action => [self, :setComputePowerUp]) if compute_attributes[:start] == '1'
......
failure _("Failed to create a compute %{compute_resource} instance %{name}: %{message}\n ") % { :compute_resource => compute_resource, :name => name, :message => e.message }, e.backtrace
end
def setUserData
logger.info "Rendering UserData template for #{name}"
template = configTemplate(:kind => "user_data")
@host = self
# For some reason this renders as 'built' in spoof view but 'provision' when
# actually used. For now, use foreman_url('built') in the template
self.compute_attributes[:user_data] = unattended_render(template.template)
self.handle_ca
return false if errors.any?
logger.info "Revoked old certificates and enabled autosign for UserData"
end
def delUserData
# Mostly copied from SSHProvision, should probably refactor to have both use a common set of PuppetCA actions
compute_attributes.merge!(:user_data => nil) # Unset any badly formatted data
# since we enable certificates/autosign via here, we also need to make sure we clean it up in case of an error
if puppetca?
respond_to?(:initialize_puppetca,true) && initialize_puppetca && delCertificate && delAutosign
end
rescue => e
failure _("Failed to remove certificates for %{name}: %{e}") % { :name => name, :e => e }, e.backtrace
end
def setComputeDetails
if vm
attrs = compute_resource.provided_attributes
......
compute_resource.update_required?(old.compute_attributes, compute_attributes.symbolize_keys)
end
def validate_compute_provisioning
return true if compute_attributes.nil?
def find_image
return nil if compute_attributes.nil?
image_uuid = compute_attributes[:image_id] || compute_attributes[:image_ref]
return true if image_uuid.blank?
img = Image.where(:uuid => image_uuid, :compute_resource_id => compute_resource_id).first
return nil if image_uuid.blank?
Image.where(:uuid => image_uuid, :compute_resource_id => compute_resource_id).first
end
def validate_compute_provisioning
return true if ( compute_attributes.nil? or (compute_attributes[:image_id] || compute_attributes[:image_ref]).blank? )
img = find_image
if img
self.image = img
else
app/models/concerns/orchestration/ssh_provision.rb
end
def ssh_provision?
compute_attributes.present? && capabilities.include?(:image)
compute_attributes.present? && capabilities.include?(:image) && !image.try(:user_data)
end
protected
app/models/image.rb
scoped_search :in => :compute_resources, :on => :name, :complete_value => :true, :rename => "compute_resource"
scoped_search :in => :architecture, :on => :id, :rename => "architecture"
scoped_search :in => :operatingsystem, :on => :id, :rename => "operatingsystem"
scoped_search :on => :user_data, :complete_value => {:true => true, :false => false}
end
app/views/images/_form.html.erb
<%= select_f f, :architecture_id, Architecture.all, :id, :to_label %>
<%= text_f f, :username, :value => @image.username || "root", :help_inline => _("The user that is used to ssh into the instance, normally cloud-user, ec2-user, ubuntu, root etc") %>
<%= image_field(f) %>
<%= checkbox_f f, :user_data, :help_inline => _("Does this image support user data input (e.g. via cloud-init)?") %>
<% if @compute_resource.provider == 'EC2' %>
<%# TODO - Get IAM roles from AWS and display in select drop %>
<%= text_f f, :iam_role, :help_inline => _("(optional) IAM Role for Fog to use when creating this image.") %>
app/views/images/index.html.erb
<table class="table table-bordered table-striped" data-table='inline'>
<thead>
<tr>
<th><%= _("Image|Name") %></th>
<th><%= _("Operating System") %></th>
<th><%= _("Image|Username") %></th>
<th><%= _("Image|Uuid") %></th>
<th><%= s_("Image|Name") %></th>
<th><%= s_("Operating System") %></th>
<th><%= s_("Image|Username") %></th>
<th><%= s_("Image|Uuid") %></th>
<th><%= s_("Image|User data") %></th>
<th></th>
</tr>
</thead>
......
<td><%= image.operatingsystem %></td>
<td><%= image.username %></td>
<td><%= image.uuid %></td>
<td><%= image.user_data? ? _("Enabled") : _("Disabled") %></td>
<td><%= action_buttons(link_to(_('Edit'), edit_compute_resource_image_path(@compute_resource, image)),
link_to(_('Destroy'), [@compute_resource, image], :confirm => _('Are you sure?'), :method => :delete)) %></td>
</tr>
db/migrate/20131223120945_add_userdata_flag_to_images.rb
class AddUserdataFlagToImages < ActiveRecord::Migration
def change
add_column :images, :user_data, :boolean, :default => false
end
end
db/seeds.rb
# Template kinds
kinds = {}
[:PXELinux, :PXEGrub, :iPXE, :provision, :finish, :script].each do |type|
[:PXELinux, :PXEGrub, :iPXE, :provision, :finish, :script, :user_data].each do |type|
kinds[type] = TemplateKind.find_by_name(type)
kinds[type] ||= TemplateKind.create :name => type
raise "Unable to create template kind: #{format_errors kinds[type]}" if kinds[type].nil? || kinds[type].errors.any?

Also available in: Unified diff