class Puppetfactory::Plugins::Docker

Public Class Methods

new(options) click to toggle source
Calls superclass method Puppetfactory::Plugins::new
# File lib/puppetfactory/plugins/docker.rb, line 10
def initialize(options)
  super(options)

  @weight = 5

  @confdir      = options[:confdir]
  @stagedir     = options[:stagedir]
  @environments = "#{@stagedir}/environments"
  @puppetcode   = options[:puppetcode]
  @master       = options[:master]
  @usersuffix   = options[:usersuffix]
  @modulepath   = options[:modulepath]
  @templatedir  = options[:templatedir]
  @container    = options[:container_name] || 'centosagent'
  @group        = options[:docker_group]   || 'docker'
  @docker_ip    = options[:docker_ip]      || `facter ipaddress_docker0`.strip
  @privileged   = options[:privileged]     || false
end

Public Instance Methods

create(username, password) click to toggle source
# File lib/puppetfactory/plugins/docker.rb, line 29
  def create(username, password)
    begin
      environment = "#{@environments}/#{Puppetfactory::Helpers.environment_name(username)}"
      binds = [
        "/var/yum:/var/yum",
        "/var/cache/rubygems:/var/cache/rubygems",
        "/var/cache/yum:/var/cache/yum",
        "/etc/pki/rpm-gpg:/etc/pki/rpm-gpg",
#        "/etc/yum.repos.d:/etc/yum.repos.d", # we can't share this because of pe_repo.repo
#        "/opt/puppetlabs/server:/opt/puppetlabs/server",
        "/home/#{username}/puppet:#{@confdir}",
        "/sys/fs/cgroup:/sys/fs/cgroup:ro"
      ]

      case @modulepath
      when :readonly
        binds.push("#{environment}:#{@puppetcode}:ro")
      when :readwrite
        binds.push("#{environment}:#{@puppetcode}")
      when :none
        #pass
      else
        raise "Uknown modulepath setting (#{@modulepath})"
      end

      container = ::Docker::Container.create(
        "Cmd" => [
          "/usr/lib/systemd/systemd"
        ],
        "Tty" => true,
        "Domainname" => @usersuffix,
        "Env" => [
          "RUNLEVEL=3",
          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
          "HOME=/root/",
          "TERM=xterm"
        ],
        "ExposedPorts" => {
          "80/tcp" => {
          }
        },
        "Hostname" => "#{username}",
        "Image" => "#{@container}",
        "HostConfig" => {
          "Privileged" => @privileged,
          "SecurityOpt" => [
            "seccomp=unconfined"
          ],
          "Tmpfs" => {
            "/run" => "",
            "/tmp" => ""
          },
          "Binds" => binds,
          "ExtraHosts" => [
            "#{@master} puppet:#{@docker_ip}"
          ],
          "PortBindings" => {
            "80/tcp" => [
              {
                "HostPort" => "#{user_port(username)}"
              }
            ]
          },
        },
        "Name" => "#{username}"
      )

      container.rename(username) # Set container name so we can identify it
      init_scripts(username)     # Create init scripts so container restarts on boot
      container.start

    rescue => e
      # fatal error, so we stop execution here
      raise "Error creating container #{username}: #{e.message}"
    end

    $logger.info "Container #{username} created"
    true
  end
delete(username) click to toggle source
# File lib/puppetfactory/plugins/docker.rb, line 109
def delete(username)
  begin
    remove_init_scripts(username)

    container = ::Docker::Container.get(username)
    output = container.delete(:force => true)
  rescue => e
    $logger.warn "Error removing container #{username}: #{e.message}"
    return false
  end

  $logger.info "Container #{username} removed"
  true
end
login() click to toggle source
# File lib/puppetfactory/plugins/docker.rb, line 153
def login
  require 'etc'
  username = Etc.getpwuid(Process.euid).name
  exec("docker exec -it #{username} su -")
end
repair(username) click to toggle source
# File lib/puppetfactory/plugins/docker.rb, line 124
def repair(username)
  begin
    container = ::Docker::Container.get(username)
    container.delete(:force => true)

    create(username, nil)
  rescue => e
    raise "Error reparing container #{username}: #{e.message}"
  end

  $logger.info "Container #{username} repaired"
  true
end
userinfo(username, extended = false) click to toggle source
# File lib/puppetfactory/plugins/docker.rb, line 138
def userinfo(username, extended = false)
  user = {
    :username => username,
    :port     => user_port(username),
    :url      => sandbox_url(username),
  }

  if extended
    user_container = ::Docker::Container.get(username).json rescue {}
    user[:container_status] = massage_container_state(user_container['State'])
  end

  user
end

Private Instance Methods

init_scripts(username) click to toggle source
# File lib/puppetfactory/plugins/docker.rb, line 187
def init_scripts(username)
  service_file = "/etc/systemd/system/docker-#{username}.service"
  File.open(service_file,"w") do |f|
    f.write ERB.new(File.read("#{@templatedir}/init_scripts.erb")).result(binding)
  end
  File.chmod(0644, service_file)
  system('chkconfig', "docker-#{username}", 'on')

  $logger.info "Init scripts created and enabled for container #{username}"
end
massage_container_state(state) click to toggle source
# File lib/puppetfactory/plugins/docker.rb, line 170
def massage_container_state(state)
  return {'Description' => 'No container.'} if state.nil?

  if state['OOMKilled']
    state['Description'] = 'Halted because host machine is out of memory.'
  elsif state['Restarting']
    state['Description'] = 'Container is restarting.'
  elsif state['Paused']
    state['Description'] = 'Container is paused.'
  elsif state['Running']
    state['Description'] = "Running since #{Time.parse(state['StartedAt']).strftime("%b %d at %I:%M%p")}"
  else
    state['Description'] = 'Halted.'
  end
  state
end
remove_init_scripts(username) click to toggle source
# File lib/puppetfactory/plugins/docker.rb, line 198
def remove_init_scripts(username)
  service_file = "/etc/systemd/system/docker-#{username}.service"
  system('chkconfig', "docker-#{username}", 'off')
  FileUtils.rm(service_file) if File.exist? service_file

  $logger.info "Init scripts for container #{username} removed"
end
sandbox_url(username) click to toggle source
# File lib/puppetfactory/plugins/docker.rb, line 160
def sandbox_url(username)
  "/port/#{user_port(username)}"
end
user_port(username) click to toggle source

TODO: We need a better way of doing this, since we're not guaranteed to always have system users.

See plugins/shell_user.rb for the other side of this coupling.
# File lib/puppetfactory/plugins/docker.rb, line 166
def user_port(username)
  Etc.getpwnam(username).uid + 3000 rescue nil
end