module Admiral::Docker

Public Class Methods

apply_layer(platform, layer_uid, ipaddress) click to toggle source
# File lib/admiral/docker.rb, line 281
def self.apply_layer(platform, layer_uid, ipaddress)

  begin
    require "admiral/layers/#{layer_uid}.rb"
  rescue LoadError
    STDERR.puts "Layer #{layer_uid} not found"
    return false
  end

  begin
    kclass = ::Admiral::Layers.const_get(Admiral::Layer.uid_to_name(layer_uid))
  rescue NameError
    STDERR.puts "Layer #{layer_uid} has a mistake"
    return false
  end
  layer = kclass.new(platform,ipaddress)

  valid = layer.verify()
  if not valid
    return false
  end

  return layer.run()
end
apply_layers(platform, ipaddress) click to toggle source
# File lib/admiral/docker.rb, line 212
def self.apply_layers(platform, ipaddress)

  layers = platform['layers']

  layers.each do | layer_uid |
    begin
      require "admiral/layers/#{layer_uid}.rb"
    rescue LoadError
      STDERR.puts "Layer #{layer_uid} not found"
      return false
    end

    begin
      kclass = ::Admiral::Layers.const_get(Admiral::Layer.uid_to_name(layer_uid))
    rescue NameError
      STDERR.puts "Layer #{layer_uid} has a mistake"
      return false
    end
    layer = kclass.new(platform,ipaddress)

    valid = layer.verify()
    if not valid
      return false
    end

    success = layer.run()
    if not success
      return false
    end

  end
  return true
end
apply_test_layers(platform, ipaddress) click to toggle source
# File lib/admiral/docker.rb, line 246
def self.apply_test_layers(platform, ipaddress)

  layers = platform['tests']

  layers.each do | layer_uid |
    begin
      require "admiral/layers/#{layer_uid}.rb"
    rescue LoadError
      STDERR.puts "Layer #{layer_uid} not found"
      return false
    end

    begin
      kclass = ::Admiral::Layers.const_get(Admiral::Layer.uid_to_name(layer_uid))
    rescue NameError
      STDERR.puts "Layer #{layer_uid} has a mistake"
      return false
    end
    layer = kclass.new(platform,ipaddress)

    valid = layer.verify()
    if not valid
      return false
    end

    success = layer.run()
    if not success
      return false
    end

  end
  return true
end
create(platform) click to toggle source
# File lib/admiral/docker.rb, line 21
def self.create (platform)

  platform_name = platform['name']
  image         = platform['image']
  docker        = platform['docker']
  hostname      = platform['hostname']
  ssh_key_file  = platform['keyfile']
  username      = platform['username']
  password      = platform['password']
  volumes       = platform['volumes']

  last_container_id = get_container_id(platform_name)
  if last_container_id
    puts "Container exist : #{last_container_id}"
  else
    dockerfile = generate_dockerfile(platform)

    volumes_cmd = ''

    if volumes.kind_of?(Array)
      volumes.each do | volume |
        if not volume['guest']
          STDERR.puts "ERROR: Volume must have 'guest' parameter"
          exit!
        else
          if volume['host']
            volumes_cmd << "-v #{volume['host']}:#{volume['guest']} "
          else
            volumes_cmd << "-v #{volume['guest']} "
          end
        end
      end
    end

    puts "=== Create image ==="

    begin
      output = Admiral::Shell.local("docker -H #{docker} build --build-arg=USERNAME='#{username}' --build-arg=PASSWORD='#{password}' --no-cache -", {:input => dockerfile}, true)
    rescue Interrupt
        STDERR.puts "Creation interrupted"
        exit!
    end

    if output

      image_id = output.gsub(/.* /m, "")
      puts "Image ID : #{image_id}"

      Dir.mkdir(".states") unless File.exists?(".states")
      f = File.open(".states/#{platform_name}.image", "w")
      f.write("#{image_id}")
      f.close

      puts "=== Create container ==="
      container_id = Admiral::Shell.local("docker -H #{docker} run -d -p 22 -h #{hostname} --privileged --cap-add ALL #{volumes_cmd} #{image_id}")

      if container_id
        puts "Container ID : #{container_id}"
        Dir.mkdir(".states") unless File.exists?(".states")
        f = File.open(".states/#{platform_name}.container", "w")
        f.write("#{container_id}")
        f.close

        output = Admiral::Shell.local("docker  -H #{docker} inspect #{container_id}")
        if output
          ipaddress = extract_ipaddress(output)
          puts "=== Configuring container ==="
          success = self.apply_layers(platform, ipaddress)
          if not success
            STDERR.puts "Failed to apply configuration layers, run destroy"
            destroy(platform)
            exit!
          end
        else
          STDERR.puts "Failed to log in container, run destroy"
          destroy(platform)
          exit!
        end
      else
        STDERR.puts "Failed to create container, run destroy"
        destroy(platform)
        exit!
      end
    end
  end
end
destroy(platform) click to toggle source
# File lib/admiral/docker.rb, line 143
def self.destroy (platform)
  platform_name = platform['name']
  docker = platform['docker']

  last_container_id = get_container_id(platform_name)
  if last_container_id
    puts "Remove container #{last_container_id}"
    Admiral::Shell.local("docker  -H #{docker} rm -f #{last_container_id}")
    File.delete(".states/#{platform_name}.container")
  else
    puts "No container"
  end

  last_image_id = get_image_id(platform_name)

  if last_container_id
    puts "Remove image #{last_image_id}"
    Admiral::Shell.local("docker  -H #{docker} rmi -f #{last_image_id}")
    File.delete(".states/#{platform_name}.image")
  else
    puts "No image"
  end
end
extract_ipaddress(container_info) click to toggle source
# File lib/admiral/docker.rb, line 360
def self.extract_ipaddress(container_info)
  data  = YAML.load(container_info).first
  return data['NetworkSettings']['IPAddress']
end
generate_dockerfile(platform) click to toggle source
# File lib/admiral/docker.rb, line 307
    def self.generate_dockerfile(platform)
      image      = platform["image"]
      username   = platform['username']
      password   = platform['password']
      pubkeyfile = platform['pubkeyfile']
      registry   = platform['registry']

      begin
        f = File.open(pubkeyfile, 'r')
        public_key = f.read().chomp()
        f.close
      rescue Errno::ENOENT  => e
         STDERR.puts "Error with public key : #{e.message}"
         exit!
      end

      from = "FROM #{registry}/#{image}\n"

      user = <<-eos
        ARG USERNAME
        ARG PASSWORD
        RUN useradd -d /home/${USERNAME} -m -s /bin/bash ${USERNAME}
        RUN echo ${USERNAME}:${PASSWORD} | chpasswd
        RUN echo "${USERNAME} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
      eos

      key = <<-eos
        RUN mkdir /home/${USERNAME}/.ssh
        RUN echo '#{public_key}' >> /home/${USERNAME}/.ssh/authorized_keys
      eos

      tmpdir = <<-eos
        RUN mkdir /tmp/${USERNAME}/
        RUN chown ${USERNAME}:${USERNAME} /tmp/${USERNAME}
      eos

      ssh_env = <<-eos
        RUN echo "AcceptEnv *" >> /etc/ssh/sshd_config
      eos

      [from, user, key, tmpdir, ssh_env].join("\n")
    end
get_container_id(platform_name) click to toggle source
# File lib/admiral/docker.rb, line 201
def self.get_container_id(platform_name)
   if File.exists?(".states/#{platform_name}.container")
      f = File.open(".states/#{platform_name}.container", "r")
      container_id = f.read()
      f.close
     return container_id
   else
     return nil
   end
end
get_image_id(platform_name) click to toggle source
# File lib/admiral/docker.rb, line 190
def self.get_image_id(platform_name)
   if File.exists?(".states/#{platform_name}.image")
      f = File.open(".states/#{platform_name}.image", "r")
      image_id = f.read()
      f.close
     return image_id
   else
     return nil
   end
end
get_ip_address(docker, container_id) click to toggle source
# File lib/admiral/docker.rb, line 350
def self.get_ip_address(docker, container_id)
  container_info = Admiral::Shell.local("docker -H #{docker} inspect #{container_id}")
  if container_info
    data  = YAML.load(container_info).first
    return data['NetworkSettings']['IPAddress']
  else
    return nil
  end
end
login(platform) click to toggle source
# File lib/admiral/docker.rb, line 167
def self.login(platform)

  container_id = get_container_id(platform['name'])
  docker = platform['docker']

  if container_id
    output = Admiral::Shell.local("docker  -H #{docker} inspect #{container_id}")
    if output
      ipaddress = extract_ipaddress(output)
      username  = platform['username']
      keyfile   = platform['keyfile']
      cmd       = "/bin/bash"

      puts "Log in to #{ipaddress}"
      Admiral::Shell.remote(ipaddress, username, keyfile, cmd)
    else
      puts "Failed to get ip address"
    end
  else
     puts "No container"
  end
end
test(platform) click to toggle source
# File lib/admiral/docker.rb, line 108
def self.test (platform)
  platform_name = platform['name']
  testdir = "test"
  if Dir.exists?(testdir)
    puts "=== Run tests ==="
    container_id = get_container_id(platform['name'])
    docker = platform['docker']

    if container_id
      output = Admiral::Shell.local("docker  -H #{docker} inspect #{container_id}")
      if output
        ipaddress = extract_ipaddress(output)
        success = self.apply_test_layers(platform, ipaddress)
        if not success
          STDERR.puts "One or more tests failed, run destroy"
          destroy(platform)
          exit!
        end
      else
        STDERR.puts "Failed to get IP address"
        destroy(platform)
        exit!
      end
    else
      STDERR.puts "Failed to container ID"
      destroy(platform)
      exit!
    end
  else
    STDERR.puts "Test directory not found"
    destroy(platform)
    exit!
  end
end
verify(platform) click to toggle source
# File lib/admiral/docker.rb, line 12
def self.verify (platform)
  @@core_parameters.each do | parameter |
    if not platform.key?(parameter)
      STDERR.puts "Parameter #{parameter} not found"
      exit!
    end
  end
end