Class: VagrantPlugins::Skytap::Action::ComposeEnvironment

Inherits:
Object
  • Object
show all
Defined in:
lib/vagrant-skytap/action/compose_environment.rb

Overview

Creates a multi-VM Skytap environment, or adds VMs to an existing environment. The source VMs (analogous to “images”) may come from various other environments and templates. We can parallelize this somewhat by adding multiple VMs per REST call, subject to the restriction that all source VMs added in a single call must be unique and must belong to the same containing environment/template. If creating a new environment from scratch, write the environment URL into the project data directory.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app, env) ⇒ ComposeEnvironment

Returns a new instance of ComposeEnvironment.



40
41
42
43
44
# File 'lib/vagrant-skytap/action/compose_environment.rb', line 40

def initialize(app, env)
  @app = app
  @env = env
  @logger = Log4r::Logger.new("vagrant_skytap::action::compose_environment")
end

Instance Attribute Details

#envObject (readonly)

Returns the value of attribute env.



38
39
40
# File 'lib/vagrant-skytap/action/compose_environment.rb', line 38

def env
  @env
end

Instance Method Details

#add_vms(environment, machines) ⇒ API::Environment

Create Skytap VMs for the given machines (if they do not exist) within the given Skytap environment.

Parameters:

  • environment (API::Environment)

    The Skytap environment, if it exists

  • machines (Array)

    Set of [Vagrant::Machine] objects

Returns:



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/vagrant-skytap/action/compose_environment.rb', line 70

def add_vms(environment, machines)
  source_vms_map = fetch_source_vms(machines)
  names_to_vm_ids = {}

  get_groupings(source_vms_map, parallel: @env[:parallel]).each do |names|
    vms_for_pass = names.collect{|name| source_vms_map[name]}

    if !environment
      @logger.debug("Creating environment from source vms: #{vms_for_pass.collect(&:id)}")
      environment = API::Environment.create!(env, vms_for_pass)
      environment.properties.write('url' => environment.url)
      vms = environment.vms
    else
      @logger.debug("Adding source vms: #{vms_for_pass.collect(&:id)}")
      vms = environment.add_vms(vms_for_pass)
    end

    vms.each_with_index {|vm, i| names_to_vm_ids[names[i]] = vm.id }
  end

  machines.each do |machine|
    machine.id = names_to_vm_ids[machine.name]
  end

  environment
end

#call(env) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/vagrant-skytap/action/compose_environment.rb', line 46

def call(env)
  environment = env[:environment]
  new_environment = !environment
  machines = env[:machines].reject(&:id)
  environment = add_vms(environment, machines)

  if new_environment
    env[:environment] = environment
    env[:ui].info(I18n.t("vagrant_skytap.environment_url", url: environment.url))
  elsif machines.present?
    env[:ui].info("Added VMs to #{environment.url}.")
  else
    env[:ui].info("No new VMs added to #{environment.url}.")
  end

  @app.call(env)
end

#fetch_source_vms(machines) ⇒ Hash

Fetch the source VMs for the given machines.

Parameters:

  • machines (Array)

    Set of [Vagrant::Machine] objects

Returns:

  • (Hash)

    mapping of machine names to [API::Vm] objects



101
102
103
104
105
106
# File 'lib/vagrant-skytap/action/compose_environment.rb', line 101

def fetch_source_vms(machines)
  machines.inject({}) do |acc, machine|
    acc[machine.name] = API::Vm.fetch(env, machine.provider_config.vm_url)
    acc
  end
end

#get_groupings(vms_map, options = {}) ⇒ Array

Group the machines to minimize calls to the REST API – unique VMs from the same environment or template can be added in a single call. The return value is a nested array of machine names, e.g.:

[:vm1, :vm4, :vm5], [:vm3], [:vm2

]

However, if the :parallel option is false, just return one machine per grouping, e.g.:

[:vm1], [:vm2], [:vm3], [:vm4], [:vm5

]

Parameters:

  • vms_map (Hash)

    Mapping of machine names to [API::Vm] objects

  • options (Hash) (defaults to: {})

Returns:

  • (Array)

    groupings (arrays) of machine names



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/vagrant-skytap/action/compose_environment.rb', line 121

def get_groupings(vms_map, options={})
  parallel = true
  parallel = options[:parallel] if options.has_key?(:parallel)
  return vms_map.keys.collect{|name| [name]} unless parallel

  # Produces nested hash, mapping configuration/template urls to
  # a map of machine names to the source VM id. (We discard the
  # parent urls -- they are just used to group the VMs.)
  groupings = vms_map.inject(Hash.new{|h,k| h[k] = {}}) do |acc, (name, vm)|
    acc[vm.parent_url][name] = vm.id
    acc
  end.values

  groupings2 = []
  groupings.each_with_index do |grouping, i|
    if grouping.values.uniq.count == grouping.values.count
      # The new VMs in the API response will be sorted
      # by the source VM ids. Sort the machines within
      # each group to match.
      groupings2 << grouping.invert.sort.collect(&:last)
    else
      # If the same source VM appears more than once in a
      # group, we have to make multiple API calls. For
      # simplicity, handle this case by creating a single
      # group for each machine.
      groupings2.concat(grouping.keys.map{|v| [v]})
    end
  end

  groupings2.sort_by{|grouping| grouping.count}.reverse
end