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

Commit

Permalink
Merge pull request #1096 from mssola/portusctl-registry
Browse files Browse the repository at this point in the history
portusctl: show a warning if the local registry has not been installed
  • Loading branch information
mssola authored Nov 17, 2016
2 parents bb4f896 + 8d64992 commit 7fb2497
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 22 deletions.
25 changes: 4 additions & 21 deletions packaging/suse/portusctl/lib/configurator.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
require_relative "registry"

# Class taking care of configuring the system according to
# what the user specified on the command line
class Configurator
include ::Portusctl::Registry

def initialize(options)
@options = options
@secret_key_base = SecureRandom.hex(64)
Expand Down Expand Up @@ -120,27 +124,6 @@ def create_database
end
end

# Creates registry's configuration
def registry
if @options["local-registry"]
# Add the certificated used by Portus to sign the JWT tokens
ssldir = "/etc/registry/ssl.crt"
FileUtils.mkdir_p(ssldir)
FileUtils.ln_sf(
"/etc/apache2/ssl.crt/#{HOSTNAME}-ca.crt",
File.join(ssldir, "portus.crt")
)

TemplateWriter.process(
"registry.yml.erb",
"/etc/registry/config.yml",
binding
)
else
TemplateWriter.render("registry.yml.erb", binding)
end
end

# Creates the config-local.yml file used by Portus
def config_local
if Process.uid != 0
Expand Down
87 changes: 87 additions & 0 deletions packaging/suse/portusctl/lib/registry.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
module Portusctl
# Contains all the needed methods for configuring the registry. You should
# only need to use the `registry` method.
module Registry
# Creates registry's configuration
def registry
if @options["local-registry"]
return unless registry_local?

# Add the certificated used by Portus to sign the JWT tokens
ssldir = "/etc/registry/ssl.crt"
FileUtils.mkdir_p(ssldir)
FileUtils.ln_sf(
"/etc/apache2/ssl.crt/#{HOSTNAME}-ca.crt",
File.join(ssldir, "portus.crt")
)

TemplateWriter.process(
"registry.yml.erb",
"/etc/registry/config.yml",
binding
)
else
TemplateWriter.render("registry.yml.erb", binding)
end
end

protected

REGISTRY_RPM = "docker-distribution-registry".freeze
ZYPPER_NOT_INSTALLED = 104 # ZYPPER_EXIT_INF_CAP_NOT_FOUND

# Checks whether the Docker Distribution package is already installed in the
# system. If it is, it will simply return true. Otherwise, it will ask the user
# whether or not to install the package first and then proceed. If the user
# doesn't want that, or some zypper command failed, then it returns false. All
# the decisions to be made by the user can be coerced with the environment
# variable "PORTUSCTL_FORCE".
def registry_local?
if Runner.safe_exec("zypper", ["se", "-ix", REGISTRY_RPM])
return true if ENV["PORTUSCTL_FORCE"]

puts "Warning: portusctl will overwrite the existing configuration."
puts "Do you want to proceed ? (Y/n)"
return user_confirm?
end

return registry_safe_install! if installed_error?
false
end

# Tries to install the RPM of Docker Distribution. It will forcefully do so if
# the "PORTUSCTL_FORCE" environment variable has been set.
def registry_safe_install!
return install_registry_rpm! if ENV["PORTUSCTL_FORCE"]

puts "You are using the `--local-registry` flag but the `docker-disitribution-registry` "\
"package is not installed in the system."
puts "Installing this package after this will overwrite the contents of the " \
"`/etc/registry/config.yml` file written by portusctl."
puts "Would you like portusctl to automatically install this package ? (Y/n)"

return install_registry_rpm! if user_confirm?

puts "Aborting: the registry will not be configured."
false
end

# Installs the RPM of Docker Distribution.
def install_registry_rpm!
Runner.safe_exec("zypper", ["-q", "-n", "--no-gpg-checks", "in", REGISTRY_RPM])
end

# Returns true if the last system() call returned a ZYPPER_NOT_INSTALLED
# error.
def installed_error?
$CHILD_STATUS == ZYPPER_NOT_INSTALLED
end

# Returns true if the user wrote either "y", "yes" (including uppercase
# variations) or nothing.
def user_confirm?
opt = $stdin.gets.chomp.downcase
opt == "" || opt == "y" || opt == "yes"
end
end
end
11 changes: 10 additions & 1 deletion packaging/suse/portusctl/lib/runner.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
# Helper file used to run external commands
class Runner
# Run a simple external command
# Run a simple external command. Keep in mind that this method will raise an
# exception if the command fails.
def self.exec(cmd, args = [])
final_cmd = Runner.escape_command(cmd, args)
unless system(final_cmd)
raise "Something went wrong while invoking: #{final_cmd}"
end
end

# Run a simple external command. This is equivalent to `Runner.exec`, but this
# method does not raise any exception. Instead, it returns a true on success
# and false otherwise.
def self.safe_exec(cmd, args = [])
final_cmd = Runner.escape_command(cmd, args)
system(final_cmd)
end

# Returns a string containing the command with its arguments all escaped.
def self.escape_command(cmd, args = [])
cmd + " " + args.map { |a| Shellwords.escape(a) }.join(" ")
Expand Down
1 change: 1 addition & 0 deletions packaging/suse/portusctl/spec/man_spec.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require_relative "spec_helper"
require "man_pages"

# Returns the path of the given markdown file.
Expand Down
97 changes: 97 additions & 0 deletions packaging/suse/portusctl/spec/registry_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
require_relative "spec_helper"

class Klass
include Portusctl::Registry

def registry_local_test?
registry_local?
end

def registry_safe_install_test!
registry_safe_install!
end

def user_confirm?
val = ENV["TEST_CONFIRM"]
val == "y" || val == "yes"
end

def installed_error?
ZYPPER_NOT_INSTALLED == ENV["TEST_EXIT_STATUS"].to_i
end
end

class Runner
def self.safe_exec_test(_cmd, _args = [])
ENV["TEST_EXIT_STATUS"].nil?
end
end

describe Portusctl::Registry do
let(:klass) { Klass.new }

before :each do
ENV["TEST_CONFIRM"] = nil
ENV["TEST_EXIT_STATUS"] = nil
ENV["PORTUSCTL_FORCE"] = nil

allow(Runner).to receive(:safe_exec) { Runner.safe_exec_test("zypper") }
end

context "PORTUSCTL_FORCE has been set" do
it "returns true if the package already exists" do
ENV["PORTUSCTL_FORCE"] = "t"
expect(klass.registry_local_test?).to be_truthy
end

it "installs the RPM" do
ENV["PORTUSCTL_FORCE"] = "t"
expect(klass.registry_safe_install_test!).to be_truthy

ENV["TEST_EXIT_STATUS"] = "1"
expect(klass.registry_safe_install_test!).to be_falsey
end
end

context "Manual execution" do
it "returns true if the package exists and the user wants to overwrite the config" do

ENV["TEST_CONFIRM"] = "y"
expect(klass.registry_local_test?).to be_truthy

ENV["TEST_CONFIRM"] = "n"
expect(klass.registry_local_test?).to be_falsey
end

it "returns false if `zypper se` failed for an unknown reason" do
ENV["TEST_EXIT_STATUS"] = "1"

expect(klass.registry_local_test?).to be_falsey
end

it "calls `registry_safe_install!` if the package has not been installed" do
ENV["TEST_EXIT_STATUS"] = "104"
allow_any_instance_of(Klass).to receive(:registry_safe_install!).and_return(true)

expect(klass.registry_local_test?).to be_truthy
end

it "installs the rpm if confirmation was given" do
# The user gives confirmation
ENV["TEST_CONFIRM"] = "y"

# The command succeeds
ENV["TEST_EXIT_STATUS"] = nil
expect(klass.registry_safe_install_test!).to be_truthy

# The command fails
ENV["TEST_EXIT_STATUS"] = "1"
expect(klass.registry_safe_install_test!).to be_falsey

# No confirmation: should fail
ENV["TEST_CONFIRM"] = "n"
ENV["TEST_EXIT_STATUS"] = nil
expect(klass.registry_safe_install_test!).to be_falsey
end
end
end

0 comments on commit 7fb2497

Please sign in to comment.