Class: Rascal::Docker::Container

Inherits:
Object
  • Object
show all
Includes:
IOHelper
Defined in:
lib/rascal/docker/container.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from IOHelper

#say, setup, #stderr, #stdin, #stdout

Constructor Details

#initialize(name, image) ⇒ Container

Returns a new instance of Container.



8
9
10
11
12
# File 'lib/rascal/docker/container.rb', line 8

def initialize(name, image)
  @name = name
  @prefixed_name = "#{NAME_PREFIX}#{name}"
  @image = image
end

Instance Attribute Details

#imageObject (readonly)

Returns the value of attribute image.



6
7
8
# File 'lib/rascal/docker/container.rb', line 6

def image
  @image
end

Instance Method Details

#cleanObject



103
104
105
106
107
108
109
110
111
112
# File 'lib/rascal/docker/container.rb', line 103

def clean
  if running?
    say "Stopping container for #{@name}"
    stop_container
  end
  if exists?
    say "Removing container for #{@name}"
    remove_container
  end
end

#create(network: nil, network_alias: nil, volumes: [], env: {}, command: []) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/rascal/docker/container.rb', line 65

def create(network: nil, network_alias: nil, volumes: [], env: {}, command: [])
  @id = Docker.interface.run(
    'container',
    'create',
    '--name', @prefixed_name,
    *(volumes.flat_map { |v| ['-v', v.to_param] }),
    *env_args(env),
    *(['--network', network.id] if network),
    *(['--network-alias', network_alias] if network_alias),
    @image,
    *command,
    output: :id,
  )
end

#download_missingObject



14
15
16
17
18
19
20
21
22
23
# File 'lib/rascal/docker/container.rb', line 14

def download_missing
  unless image_exists?
    say "Downloading image for #{@name}"
    Docker.interface.run(
      'pull',
      @image,
      stdout: stdout,
    )
  end
end

#exists?Boolean

Returns:

  • (Boolean)


29
30
31
# File 'lib/rascal/docker/container.rb', line 29

def exists?
  !!id
end

#idObject



125
126
127
128
129
130
131
132
133
134
# File 'lib/rascal/docker/container.rb', line 125

def id
  @id ||= Docker.interface.run(
    'container',
    'ps',
    '--all',
    '--quiet',
    '--filter', "name=^/#{@prefixed_name}$",
    output: :id,
  )
end

#remove_if_network_missing(network) ⇒ Object

Docker resolves a container's network by the id it recorded when the container was created, and refuses to start it once that network is gone:

failed to set up container networking: network 36243f82141a... not found

docker network prune (and docker system prune) leaves exactly that behind, because it removes networks whose containers are all stopped — the normal state of an environment between runs. Reconnecting does not help, since docker resolves the recorded id before it looks at the container's current endpoints, so the container has to go. Nothing in a service container is worth preserving; #start creates a new one.



45
46
47
48
49
50
51
52
53
# File 'lib/rascal/docker/container.rb', line 45

def remove_if_network_missing(network)
  return unless exists?
  attached = attached_network_ids
  return if attached.empty? || attached.include?(network.id)

  say "Removing container for #{@name}, its network no longer exists"
  remove_container
  @id = nil
end

#run_and_attach(*command, env: {}, network: nil, volumes: [], working_dir: nil, allow_failure: false, tty: true) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/rascal/docker/container.rb', line 80

def run_and_attach(*command, env: {}, network: nil, volumes: [], working_dir: nil, allow_failure: false, tty: true)
  Docker.interface.run_and_attach(
    'container',
    'run',
    '--rm',
    '-a', 'STDOUT',
    '-a', 'STDERR',
    *(['-a', 'STDIN', '--interactive', '--tty'] if tty),
    *(['-w', working_dir] if working_dir),
    *(volumes.flat_map { |v| ['-v', v.to_param] }),
    *env_args(env),
    *(['--network', network.id] if network),
    @image,
    *command,
    redirect_io: {
      out: stdout,
      err: stderr,
      in: stdin,
    },
    allow_failure: allow_failure,
  )
end

#running?Boolean

Returns:

  • (Boolean)


25
26
27
# File 'lib/rascal/docker/container.rb', line 25

def running?
  !!container_info&.dig('State', 'Running')
end

#start(network: nil, network_alias: nil, volumes: [], env: {}, command: []) ⇒ Object



55
56
57
58
59
60
61
62
63
# File 'lib/rascal/docker/container.rb', line 55

def start(network: nil, network_alias: nil, volumes: [], env: {}, command: [])
  say "Starting container for #{@name}"
  create(network: network, network_alias: network_alias, volumes: volumes, env: env, command: command) unless exists?
  Docker.interface.run(
    'container',
    'start',
    id,
  )
end

#update(skip: []) ⇒ Object



114
115
116
117
118
119
120
121
122
123
# File 'lib/rascal/docker/container.rb', line 114

def update(skip: [])
  return if skip.include?(@image)
  say "Updating image #{@image}"
  Docker.interface.run(
    'pull',
    @image,
    stdout: stdout,
  )
  @image
end