Skip to content

Commit

Permalink
Merge branch 'feature/volumes-from-rework-78132376'
Browse files Browse the repository at this point in the history
  • Loading branch information
rupakg committed Oct 2, 2014
2 parents 044b886 + 8ececad commit 3fadd70
Show file tree
Hide file tree
Showing 32 changed files with 381 additions and 18 deletions.
7 changes: 7 additions & 0 deletions app/builders/template_builder/from_fig.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def image_from_fig_service(name, service_def)
image.expose = service_def['expose']
image.volumes = volumes(service_def['volumes'])
image.environment = service_def['environment']
image.volumes_from = shared_volumes(service_def['volumes_from'])
end
end

Expand All @@ -54,5 +55,11 @@ def volumes(volumes_array)
end
end

def shared_volumes(vol_from_array)
Array(vol_from_array).map do |vol_from|
{ 'service' => vol_from }
end
end

end
end
3 changes: 2 additions & 1 deletion app/controllers/apps_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ def app_params
environment: [[:variable, :value, :required]],
ports: [[:host_interface, :host_port, :container_port, :proto]],
expose: [],
volumes: [[:host_path, :container_path]]
volumes: [[:host_path, :container_path]],
volumes_from: [[:service]]
)
end

Expand Down
1 change: 1 addition & 0 deletions app/controllers/services_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def service_params(extras=nil)
ports: [[:host_interface, :host_port, :container_port, :proto]],
expose: [],
volumes: [[:host_path, :container_path]],
volumes_from: [[:service_id]],
links: [[:service_id, :alias]],
environment: [[:variable, :value, :required]]
)
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/templates_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ def template_create_params
expose: [],
links: [[:service_id, :alias]],
environment: [[:variable, :value, :required]],
links: [[:service_id, :alias]],
ports: [[:host_interface, :host_port, :container_port, :proto]]
ports: [[:host_interface, :host_port, :container_port, :proto]],
volumes_from: [[:service_id]]
]]
)
end
Expand Down
7 changes: 7 additions & 0 deletions app/models/concerns/docker_runnable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ def docker_run_string
expose_flags,
environment_flags,
volume_flags,
volumes_from_flags,
from,
command
].flatten.compact.join(' ').strip
Expand Down Expand Up @@ -64,4 +65,10 @@ def volume_flags
end
end

def volumes_from_flags
return unless volumes_from && volumes_from.present?
volumes_from.map do |svol|
"--volumes-from #{svol.exported_from_service_name}"
end
end
end
5 changes: 5 additions & 0 deletions app/models/converters/service_converter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def to_image
expose: service.expose,
environment: service.environment,
volumes: service.volumes,
volumes_from: service_volumes_from,
command: service.command,
type: service.type
)
Expand All @@ -33,5 +34,9 @@ def service_links
service.links.map { |link| { 'service' => link.linked_to_service.name, 'alias' => link.alias } }
end

def service_volumes_from
service.volumes_from.map { |shared_vol| { 'service' => shared_vol.exported_from_service.name } }
end

end
end
15 changes: 15 additions & 0 deletions app/models/converters/template_converter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ def to_app
linked_from_service.links = service_links_from_image(image)
end

# Set-up shared volumes for services
template.images.each do |image|
next unless image.volumes_from?
the_service = find_service(image.name)
the_service.volumes_from = shared_volumes_from_image(image)
end

App.new(
name: template.name,
from: "Template: #{template.name}",
Expand Down Expand Up @@ -62,6 +69,14 @@ def service_links_from_image(image)
end
end

def shared_volumes_from_image(image)
image.volumes_from.map do |vol_from|
SharedVolume.new(
exported_from_service: find_service(vol_from['service'])
)
end
end

def find_service(name)
services.find { |service| service.name == name }
end
Expand Down
2 changes: 2 additions & 0 deletions app/models/image.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class Image < ActiveRecord::Base
serialize :expose, Array
serialize :environment, Array
serialize :volumes, Array
serialize :volumes_from, Array

belongs_to :template

Expand All @@ -17,4 +18,5 @@ class Image < ActiveRecord::Base
validates :ports, has_container_ports: true, has_unique_ports: true
validates :links, has_link_alias: true, service_link_exists: true
validates :volumes, has_container_paths: true
validates :volumes_from, shared_volume_service_exists: true
end
18 changes: 18 additions & 0 deletions app/models/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ class Service < ActiveRecord::Base
class_name: 'ServiceLink',
foreign_key: 'linked_from_service_id',
dependent: :destroy
has_many :volumes_from,
class_name: 'SharedVolume',
foreign_key: 'mounted_on_service_id',
dependent: :destroy

# Only here for the dependent destroy. Want to remove any service link joins that may point
# to this model as the 'linked_to_service'
Expand All @@ -23,6 +27,13 @@ class Service < ActiveRecord::Base
foreign_key: 'linked_to_service_id',
dependent: :destroy

# Only here for the dependent destroy. Want to remove any service mount joins that may point
# to this model as the 'mounted_on_service'
has_many :mounted_volumes,
class_name: 'SharedVolume',
foreign_key: 'exported_from_service_id',
dependent: :destroy

serialize :ports, Array
serialize :expose, Array
serialize :environment, Array
Expand Down Expand Up @@ -90,6 +101,13 @@ def update_with_relationships(attributes)
)
end

attributes[:volumes_from] ||= []
attributes[:volumes_from].map! do |svol|
self.volumes_from.find_or_initialize_by(
exported_from_service_id: svol[:service_id]
)
end

attributes[:volumes] ||= []
attributes[:volumes].map! { |vol| vol.to_hash }

Expand Down
23 changes: 23 additions & 0 deletions app/models/shared_volume.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
class SharedVolume < ActiveRecord::Base
self.table_name = 'shared_volumes'

belongs_to :exported_from_service, class_name: 'Service'

validates :exported_from_service, uniqueness: { scope: :mounted_on_service_id }, presence: true
validate :cannot_mount_self

def exported_from_service_name
"#{exported_from_service.name}"
end

private

def cannot_mount_self
if mounted_on_service_id.present? &&
exported_from_service_id.present? &&
mounted_on_service_id == exported_from_service_id

errors.add(:base, "can't mount self")
end
end
end
3 changes: 2 additions & 1 deletion app/serializers/image_serializer.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
class ImageSerializer < ActiveModel::Serializer
self.root = false

attributes :id, :category, :name, :source, :description, :type, :expose, :ports, :links, :environment, :volumes, :command
attributes :id, :category, :name, :source, :description, :type, :expose,
:ports, :links, :environment, :volumes, :volumes_from, :command

def category
object.categories.first unless object.categories.blank?
Expand Down
2 changes: 2 additions & 0 deletions app/serializers/service_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class ServiceSerializer < ActiveModel::Serializer

has_many :links, serializer: ServiceLinkSerializer

has_many :volumes_from, serializer: SharedVolumeSerializer

def load_state
service_state[:load_state]
end
Expand Down
14 changes: 14 additions & 0 deletions app/serializers/shared_volume_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class SharedVolumeSerializer < ActiveModel::Serializer
self.root = false

attributes :service_id, :service_name, :errors

def service_id
object.exported_from_service.id
end

def service_name
object.exported_from_service.name
end

end
1 change: 1 addition & 0 deletions app/serializers/template_file_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class TemplateFileImageSerializer < ActiveModel::Serializer
:links,
:environment,
:volumes,
:volumes_from,
:command

def category
Expand Down
14 changes: 14 additions & 0 deletions app/validators/shared_volume_service_exists_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class SharedVolumeServiceExistsValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return unless value.present? && record.respond_to?(:template)
value.each do |shared_vol|
next if template_image_names_for(record).include? shared_vol['service']
record.errors[attribute] << 'service exporting shared volumes must exist'
break
end
end

def template_image_names_for(model)
model.template ? model.template.images.map(&:name) : []
end
end
12 changes: 12 additions & 0 deletions db/migrate/20140929181001_create_shared_volumes.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class CreateSharedVolumes < ActiveRecord::Migration
def change
create_table :shared_volumes do |t|
t.references :exported_from_service, index: true
t.references :mounted_on_service, index: true

t.timestamps
end

add_index :shared_volumes, [:exported_from_service_id, :mounted_on_service_id], unique: true, name: 'index_shared_volume_keys'
end
end
5 changes: 5 additions & 0 deletions db/migrate/20140929193656_add_volumes_from_to_images.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddVolumesFromToImages < ActiveRecord::Migration
def change
add_column :images, :volumes_from, :text
end
end
14 changes: 13 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20140919202446) do
ActiveRecord::Schema.define(version: 20140929193656) do

create_table "app_categories", force: true do |t|
t.string "name"
Expand Down Expand Up @@ -52,6 +52,7 @@
t.integer "template_id"
t.datetime "created_at"
t.datetime "updated_at"
t.text "volumes_from"
end

add_index "images", ["image_id"], name: "index_images_on_image_id", unique: true
Expand Down Expand Up @@ -98,6 +99,17 @@
add_index "services", ["app_id"], name: "index_services_on_app_id"
add_index "services", ["name"], name: "index_services_on_name"

create_table "shared_volumes", force: true do |t|
t.integer "exported_from_service_id"
t.integer "mounted_on_service_id"
t.datetime "created_at"
t.datetime "updated_at"
end

add_index "shared_volumes", ["exported_from_service_id", "mounted_on_service_id"], name: "index_shared_volume_keys", unique: true
add_index "shared_volumes", ["exported_from_service_id"], name: "index_shared_volumes_on_exported_from_service_id"
add_index "shared_volumes", ["mounted_on_service_id"], name: "index_shared_volumes_on_mounted_on_service_id"

create_table "template_repos", force: true do |t|
t.string "name"
t.datetime "created_at"
Expand Down
2 changes: 2 additions & 0 deletions spec/builders/template_builder/from_fig_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
expect(subject.images.find_by(name: 'db').volumes).to be_blank
expect(subject.images.find_by(name: 'web').expose).to be_blank
expect(subject.images.find_by(name: 'db').expose).to eq(['3306'])
expect(subject.images.find_by(name: 'web').volumes_from).to be_blank
expect(subject.images.find_by(name: 'db').volumes_from).to eq([{ 'service' => 'web' }])
end
end

Expand Down
1 change: 1 addition & 0 deletions spec/controllers/templates_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
{ 'variable' => 'GIT_REPO', 'value' => 'https://github.com/fermayo/hello-world-php.git' }
],
'volumes' => [],
'volumes_from' => [{ 'service_id' => '3' }],
'command' => '/start web'
}
]
Expand Down
11 changes: 11 additions & 0 deletions spec/models/converters/service_converter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,16 @@
service1.categories.build(app_category: app_categories(:category1))
end
end

context 'when handling services with volumes_from' do
before do
service1.volumes_from.create(exported_from_service: services(:service2))
end

it 'populates the image with volumes_from' do
expect(subject.to_image.volumes_from).to eql [{ 'service' => 'my-other-service' }]
end
end

end
end
31 changes: 31 additions & 0 deletions spec/models/converters/template_converter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
environment: { var: 'val' },
command: '/boom shaka',
volumes: ['volumes'],
volumes_from: ['service1'],
type: 'mysql'
)
end
Expand Down Expand Up @@ -121,5 +122,35 @@
end
end

context 'with shared volumes' do

let(:image1) { Image.new(name: 'I1', source: 'I1:latest') }
let(:image2) { Image.new(name: 'I2', source: 'I2:latest') }

before do
image2.volumes_from = [{ 'service' => 'I1' }]
template.images = [image1, image2]
end

it 'creates a service for both images' do
app = subject.to_app
expect(app.services.size).to eq 2
end

it 'creates shared volumes where appropriate' do
app = subject.to_app
s1, s2 = app.services
expect(s1.volumes_from.size).to eq 0
expect(s2.volumes_from.size).to eq 1
end

it 'shared volumes linked to the services correctly' do
app = subject.to_app
s1, s2 = app.services
expect(s2.volumes_from.first.exported_from_service_id).to eq s2.id
expect(s2.volumes_from.first.mounted_on_service_id).to eq s1.id
end
end

end
end
Loading

0 comments on commit 3fadd70

Please sign in to comment.