Class: ChefMetalLXC::LXCProvisioner

Inherits:
ChefMetal::Provisioner
  • Object
show all
Includes:
Chef::Mixin::ShellOut
Defined in:
lib/chef_metal_lxc/lxc_provisioner.rb

Overview

Provisions machines in lxc.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(lxc_path = nil) ⇒ LXCProvisioner

Returns a new instance of LXCProvisioner.



15
16
17
# File 'lib/chef_metal_lxc/lxc_provisioner.rb', line 15

def initialize(lxc_path = nil)
  @lxc_path = lxc_path || LXC.global_config_item('lxc.lxcpath')
end

Instance Attribute Details

#lxc_pathObject (readonly)

Returns the value of attribute lxc_path.



19
20
21
# File 'lib/chef_metal_lxc/lxc_provisioner.rb', line 19

def lxc_path
  @lxc_path
end

Instance Method Details

#acquire_machine(action_handler, node) ⇒ Object

Acquire a machine, generally by provisioning it. Returns a Machine object pointing at the machine, allowing useful actions like setup, converge, execute, file and directory. The Machine object will have a “node” property which must be saved to the server (if it is any different from the original node object).

## Parameters action_handler - the action_handler object that provides context. node - node object (deserialized json) representing this machine. If

the node has a provisioner_options hash in it, these will be used
instead of options provided by the provisioner.  TODO compare and
fail if different?
node will have node['normal']['provisioner_options'] in it with any options.
It is a hash with this format:

   -- provisioner_url: lxc:<lxc_path>
   -- template: template name
   -- template_options: additional arguments for templates
   -- backingstore: backing storage (lvm, thinpools, btrfs etc)
   -- config_file: <path> path to LXC  file a la https://wiki.archlinux.org/index.php/Linux_Containers#Configuration_file
   -- extra_config: { 'key' => 'value', ... } a set of LXC config key/value pairs to individually set.  Merges with, and overrides any values in config_file.

node['normal']['provisioner_output'] will be populated with information
about the created machine.  For lxc, it is a hash with this
format:

   -- provisioner_url: lxc:<lxc_path>
   -- name: container name


51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/chef_metal_lxc/lxc_provisioner.rb', line 51

def acquire_machine(action_handler, node)
  # TODO verify that the existing provisioner_url in the node is the same as ours

  # Set up the modified node data
  provisioner_options = node['normal']['provisioner_options']
  provisioner_output = node['normal']['provisioner_output'] || {
    'provisioner_url' =>   "lxc:#{lxc_path}",
    'name' => node['name']
  }

  # Create the container if it does not exist
  ct = LXC::Container.new(provisioner_output['name'], lxc_path)
  unless ct.defined?
    action_handler.perform_action "create lxc container #{provisioner_output['name']}" do
      #
      # Set config
      #
      # TODO if config file changes, reload container?
      if provisioner_options['config_file']
        ct.load_config(provisioner_options['config_file'])
      end
      if provisioner_options['extra_config']
        provisioner_options['extra_config'].each_pair do |key, value|
          ct.set_config_item(key, value)
        end
      end

      #
      # Create the machine
      #
      ct.create(provisioner_options['template'], provisioner_options['backingstore'], 0, provisioner_options['template_options'])
    end
  end

  # Unfreeze the frozen
  if ct.state == :frozen
    action_handler.perform_action "unfreeze lxc container #{provisioner_output['name']} (state is #{ct.state})" do
      ct.unfreeze
    end
  end

  # Get stopped containers running
  unless ct.running?
    action_handler.perform_action "start lxc container #{provisioner_output['name']} (state is #{ct.state})" do
      # Have to shell out to lxc-start for now, ct.start holds server sockets open!
      lxc_start = "lxc-start -d -n #{Shellwords.escape(provisioner_output['name'])}"
# TODO add ability to change options on start
#          if provisioner_options['config_file']
#            lxc_start << " -f #{Shellwords.escape(provisioner_options['config_file'])}"
#          end
#          if provisioner_options['extra_config']
#            provisioner_options['extra_config'].each_pair do |key,value|
#              lxc_start << " -s #{Shellwords.escape("#{key}=#{value}")}"
#            end
#          end
      shell_out!(lxc_start)
#          ct.start
    end
  end

  node['normal']['provisioner_output'] = provisioner_output
  # Create machine object for callers to use
  machine_for(node)
end

#connect_to_machine(node) ⇒ Object

Connect to machine without acquiring it



117
118
119
# File 'lib/chef_metal_lxc/lxc_provisioner.rb', line 117

def connect_to_machine(node)
  machine_for(node)
end

#delete_machine(action_handler, node) ⇒ Object



121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/chef_metal_lxc/lxc_provisioner.rb', line 121

def delete_machine(action_handler, node)
  if node['normal'] && node['normal']['provisioner_output']
    provisioner_output = node['normal']['provisioner_output']
    ct = LXC::Container.new(provisioner_output['name'], lxc_path)
    if ct.defined?
      action_handler.perform_action "delete lxc container #{provisioner_output['name']}" do
        ct.destroy
      end
    end
  end
  convergence_strategy_for(node).delete_chef_objects(action_handler, node)
end

#stop_machine(action_handler, node) ⇒ Object



134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/chef_metal_lxc/lxc_provisioner.rb', line 134

def stop_machine(action_handler, node)
  provisioner_options = node['normal']['provisioner_options']
  if node['normal'] && node['normal']['provisioner_output']
    provisioner_output = node['normal']['provisioner_output']
    ct = LXC::Container.new(provisioner_output['name'], lxc_path)
    if ct.running?
      action_handler.perform_action "delete lxc container #{provisioner_output['name']}" do
        ct.stop
      end
    end
  end
end