Skip to content

Commit

Permalink
Refactor runCustom. Create ServiceRun and InstanceOnDemand classes
Browse files Browse the repository at this point in the history
  • Loading branch information
sarahloui committed Sep 13, 2023
1 parent 60f0146 commit f7e4e37
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 31 deletions.
1 change: 1 addition & 0 deletions lib/cove.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
require_relative "cove/role"
require_relative "cove/deployment"
require_relative "cove/instance"
require_relative "cove/instance_on_demand"
require_relative "cove/entity_labels"
require_relative "cove/environment_file"
require_relative "cove/configuration"
Expand Down
26 changes: 3 additions & 23 deletions lib/cove/cli/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,10 @@ def ps(service_name)

desc "run SERVICE with COMMANDS", "Run a container with custom commands for SERVICE"
option :role
option :instance
option :host
def runCustom(service_name, custom_command)
def runCustom(service_name, command)
service = Cove.registry.services[service_name]
custom_cmd = custom_command.split
command = command.split

role = if options[:role]
Cove.registry.roles_for_service(service).bsearch { |x| x.name == options[:role] }
Expand All @@ -56,26 +55,7 @@ def runCustom(service_name, custom_command)
role.hosts.first
end

index = options[:instance] || 1

Cove.output.puts "service: #{service_name}, role: #{role.name}, host: #{host.name}, instance: #{index}, commands: #{custom_command}."

version = Digest::SHA2.hexdigest([role.id, role.image, custom_cmd, role.environment_variables, []].to_json)[0..12]
deployment = Cove::Deployment.new(role, version: version)
instance = Cove::Instance.new(deployment, index)
desired_container = Cove::DesiredContainer.from(instance)
desired_container.command = custom_cmd
desired_container.ports = []

ssh_cmd = ["ssh", "-t", host.ssh_destination_string]
run_cmd = Cove::Command::Builder.run_container(desired_container)

cmd = ssh_cmd + run_cmd

run_locally do
info "Connecting to host #{host.name} and running container #{desired_container.name} via #{cmd.join(" ")}"
Kernel.exec(*cmd)
end
Cove::Invocation::ServiceRun.new(registry: Cove.registry, service: service, custom_cmd: command, role: role, host: host).invoke
end
end
end
Expand Down
8 changes: 6 additions & 2 deletions lib/cove/command/builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ def self.start_container(*containers)
[:docker, "container", "start", *containers.flatten]
end

def self.start_attached_container(container)
[:docker, "container", "start", "--attach", "-i", container]
end

# @param [String] containers The name or id of the container(s) to stop
# @param [Integer] time
def self.stop_container(*containers, time: nil)
Expand All @@ -20,8 +24,8 @@ def self.delete_container(*containers)

# @param [Cove::DesiredContainer] config
# @return [Array] The command to create the container
def self.create_container(config)
Docker::Container::Create.build(image: config.image, name: config.name, labels: config.labels, command: config.command, environment_files: config.environment_files, ports: config.ports, mounts: config.mounts)
def self.create_container(config, remove: false, interactive: false)
Docker::Container::Create.build(image: config.image, name: config.name, remove: remove, interactive: interactive, labels: config.labels, command: config.command, environment_files: config.environment_files, ports: config.ports, mounts: config.mounts)
end

# @param [Cove::DesiredContainer] config
Expand Down
36 changes: 36 additions & 0 deletions lib/cove/instance_on_demand.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
module Cove
class InstanceOnDemand
# @return [Cove::Deployment]
attr_reader :deployment
# @return [Cove::Role]
delegate :role, to: :deployment
# @return [Cove::Service]
delegate :service, to: :role
# @return [String] The version of the deployment
delegate :version, to: :deployment
# @return [String] The command to run in the container
attr_reader :command
# @return [Array<Hash>] The port mapping to run in the container
attr_reader :ports
# @return [Array<Hash>] The volumes to mount to the container
delegate :mounts, to: :role
# @return [String] The image of the container
delegate :image, to: :role
# @return [Cove::EntityLabels] The labels of the container
delegate :labels, to: :deployment

# @param deployment [Cove::Deployment] The deployment the container is part of
def initialize(deployment, command)
@deployment = deployment
@command = command
@ports = []
end

def name
"#{service.name}-#{role.name}-#{version}"
end

def labels
end
end
end
1 change: 1 addition & 0 deletions lib/cove/invocation.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require_relative "invocation/service_up"
require_relative "invocation/service_down"
require_relative "invocation/service_ps"
require_relative "invocation/service_run"
63 changes: 63 additions & 0 deletions lib/cove/invocation/service_run.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
module Cove
module Invocation
class ServiceRun
include SSHKit::DSL

# @return [Cove::Registry]
attr_reader :registry
# @return [Cove::Service]
attr_reader :service
attr_reader :custom_cmd
attr_reader :role
attr_reader :host

# @param registry [Cove::Registry]
# @param service [Cove::Service]
# @param custom_cmd [Array<String>]
# @param role [Cove::Role]
# @param host [Cove::Host]
def initialize(registry:, service:, custom_cmd:, role:, host:)
@service = service
@registry = registry
@custom_cmd = custom_cmd
@role = role
@host = host
end

# @return nil
def invoke
Cove.output.puts "service: #{service.name}, role: #{role.name}, host: #{host.name}, commands: #{custom_cmd}."
deployment = Cove::Deployment.new(role)
instance_on_demand = Cove::InstanceOnDemand.new(deployment, custom_cmd)
desired_container = Cove::DesiredContainer.new(
name: instance_on_demand.name,
image: instance_on_demand.image,
command: instance_on_demand.command,
labels: instance_on_demand.labels,
environment_files: [EnvironmentFile.new(instance_on_demand.deployment).host_file_path],
version: instance_on_demand.version,
ports: instance_on_demand.ports,
mounts: instance_on_demand.mounts
)
ssh_cmd = ["ssh", "-t", host.ssh_destination_string]
create_cmd = Cove::Command::Builder.create_container(desired_container, remove: true, interactive: true)
start_cmd = Cove::Command::Builder.start_attached_container(desired_container.name)
create_cmd = create_cmd.map { |el| el.to_s }
start_cmd = ssh_cmd + start_cmd
start_cmd = start_cmd.map { |el| el.to_s }

on(host.sshkit_host) do
Steps::EnsureEnvironmentFileExists.call(self, deployment)
Steps::PullImage.call(self, deployment)
info "Creating container #{desired_container.name}"
execute(*create_cmd)
end

run_locally do
info "Starting container #{desired_container.name}"
Kernel.exec(*start_cmd)
end
end
end
end
end
16 changes: 10 additions & 6 deletions spec/cove/cli/service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,18 @@
describe "#runCustom" do
it "runs a container with a custom command" do
Cove.init(config: "spec/fixtures/configs/basic/")
service = Cove.registry.services["nginx"]
role = Cove.registry.roles_for_service(service).first
host = role.hosts.first

expect(Kernel).to receive(:exec)
expect(Cove::Invocation::ServiceRun).to receive(:new).with(
registry: Cove.registry,
service: service,
custom_cmd: ["echo", "hello"],
role: role,
host: host
) { double(invoke: nil) }
described_class.new.invoke(:runCustom, ["nginx"], ["echo hello"])

expect(Cove.output.string).to match(/nginx/)
expect(Cove.output.string).to match(/web/)
expect(Cove.output.string).to match(/host1/)
expect(Cove.output.string).to match(/echo hello/)
end
end
end

0 comments on commit f7e4e37

Please sign in to comment.