Skip to content
This repository has been archived by the owner on Jan 5, 2023. It is now read-only.

Feature: compose 'memory' #22

Merged
merged 4 commits into from
Feb 25, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,26 @@ DockerCompose.version
# Loading a compose file
compose = DockerCompose.load('[path to docker compose file]')

# 'Load' method accepts a second argument, telling to do load or not
# containers started previously by this compose file.
#
# So, loading a compose file + containers started by this compose previously
compose = DockerCompose.load('[path to docker compose file]', true)

# Accessing containers
compose.containers # access all containers
compose.containers['container_label'] # access a container by its label (DEPRECATED)
compose.get_containers_by(label: 'foo', name: 'bar') # Returns an array of all containers with label = 'foo' and name = bar

# Containers names are generated using the pattern below:
# [Directory name]_[Container label]_[Sequential ID]
#
# So, you can access a container by its full name...
compose.get_containers_by(name: 'myawessomedir_foobar_1')

# ... or by its given name (ignores both prefix and suffix)
compose.get_containers_by_given_name('foobar')

# Starting containers (and their dependencies)
compose.start # start all containers
compose.start(['container1', 'container2', ...]) # start a list of specific containers
Expand Down
41 changes: 37 additions & 4 deletions lib/docker-compose.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,30 @@ def self.docker_client
# Load a given docker-compose file.
# Returns a new Compose object
#
def self.load(filepath)
def self.load(filepath, do_load_running_containers = false)
unless File.exist?(filepath)
raise ArgumentError, 'Compose file doesn\'t exists'
end

compose = Compose.new

# Create containers from compose file
_compose_entries = YAML.load_file(filepath)
_compose_entries.each do |entry|
compose.add_container(create_container(entry))

if _compose_entries
_compose_entries.each do |entry|
compose.add_container(create_container(entry))
end
end

# Load running containers
if do_load_running_containers
Docker::Container
.all(all: true)
.select {|c| c.info['Names'].last.match(/\A\/#{ComposeUtils.dir_name}\w*/) }
.each do |container|
compose.add_container(load_running_container(container))
end
end

# Perform containers linkage
Expand All @@ -50,5 +64,24 @@ def self.create_container(attributes)
})
end

private_class_method :create_container
def self.load_running_container(container)
info = container.json

container_args = {
label: info['Name'].split(/_/)[1] || '',
full_name: info['Name'],
image: info['Image'],
build: nil,
links: info['HostConfig']['Links'],
ports: ComposeUtils.format_ports_from_running_container(info['NetworkSettings']['Ports']),
volumes: info['Config']['Volumes'],
command: info['Config']['Cmd'].join(' '),
environment: info['Config']['Env'],
labels: info['Config']['Labels']
}

ComposeContainer.new(container_args, container)
end

private_class_method :create_container, :load_running_container
end
15 changes: 15 additions & 0 deletions lib/docker-compose/models/compose.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ def initialize
# Add a new container to compose
#
def add_container(container)
# Avoid duplicated labels on compose
while @containers.has_key?(container.attributes[:label]) do
container.attributes[:label].succ!
end

@containers[container.attributes[:label]] = container
true
end
Expand All @@ -28,6 +33,16 @@ def get_containers_by(params)
end
end

#
# Select containers based on its given name
# (ignore basename)
#
def get_containers_by_given_name(given_name)
@containers.select { |label, container|
container.attributes[:name].match(/#{ComposeUtils.dir_name}_#{given_name}_\d+/)
}.values
end

#
# Create link relations among containers
#
Expand Down
8 changes: 4 additions & 4 deletions lib/docker-compose/models/compose_container.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
require_relative '../utils/compose_utils'

class ComposeContainer
attr_reader :attributes, :container, :dependencies
attr_reader :attributes, :internal_image, :container, :dependencies

def initialize(hash_attributes)
def initialize(hash_attributes, docker_container = nil)
@attributes = {
label: hash_attributes[:label],
name: hash_attributes[:name].nil? ? hash_attributes[:label] : hash_attributes[:name],
name: hash_attributes[:full_name] || ComposeUtils.generate_container_name(hash_attributes[:name], hash_attributes[:label]),
image: ComposeUtils.format_image(hash_attributes[:image]),
build: hash_attributes[:build],
links: ComposeUtils.format_links(hash_attributes[:links]),
Expand All @@ -22,7 +22,7 @@ def initialize(hash_attributes)

# Docker client variables
@internal_image = nil
@container = nil
@container = docker_container
@dependencies = []
end

Expand Down
64 changes: 64 additions & 0 deletions lib/docker-compose/utils/compose_utils.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,29 @@
module ComposeUtils
@dir_name = File.split(Dir.pwd).last.gsub(/[-_]/, '')
@current_container_id = nil

#
# Returns the directory name where compose
# file is saved (used in container naming)
#
def self.dir_name
@dir_name
end

#
# Provides the next available ID
# to container names
#
def self.next_available_id
if @current_container_id.nil?
# Discovery the max id used by already running containers
# (default to '0' if no container is running)
@current_container_id = Docker::Container.all(all: true).map {|c| c.info['Names'].last.split(/_/).last.to_i}.flatten.max || 0
end

@current_container_id += 1
end

#
# Format a given docker image in a complete structure (base image + tag)
#
Expand Down Expand Up @@ -58,6 +83,30 @@ def self.format_port(port_entry)
compose_port
end

#
# Format ports from running container
#
def self.format_ports_from_running_container(port_entry)
entries = []
container_port = nil
host_ip = nil
host_port = nil

if port_entry.nil?
return entries
end

port_entry.each do |key, value|
container_port = key.gsub(/\D/, '').to_i
host_ip = value.first['HostIp']
host_port = value.first['HostPort']

entries << "#{container_port}:#{host_ip}:#{host_port}"
end

entries
end

#
# Generate a pair key:hash with
# format {service:label}
Expand All @@ -83,4 +132,19 @@ def self.format_links(links_array)

links
end

#
# Generate a container name, based on:
# - directory where the compose file is saved;
# - container name (or label, if name isn't provided);
# - a sequential index;
#
def self.generate_container_name(container_name, container_label)
label = container_name.nil? ? container_label : container_name
index = next_available_id

"#{@dir_name}_#{label}_#{index}"
end

private_class_method :next_available_id
end
2 changes: 1 addition & 1 deletion lib/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module DockerCompose
def self.version
"1.0.5"
"1.1.0"
end
end
Loading