Skip to content

Commit

Permalink
Add support for multiple self-update URLs in SCC/SMT
Browse files Browse the repository at this point in the history
  • Loading branch information
imobachgs committed Jul 25, 2016
1 parent 235beb6 commit 5fe00cd
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 80 deletions.
161 changes: 99 additions & 62 deletions src/lib/installation/clients/inst_update_installer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,32 @@ def main
end
end

# Tries to update the installer
#
# It also shows feedback to the user in case of error.
#
# Errors handling:
#
# * A repository is not found: warn the user if she/he is using
# a custom URL.
# * Could not fetch update from repository: report the user about
# this error.
# * Repository could not be probed: suggest checking network
# configuration if URL has a REMOTE_SCHEME.
#
# @return [Boolean] true if installer was updated; false otherwise.
def update_installer
updated = self_update_urls.map { |u| add_repository(u) }.any?

if updated
log.info("Applying installer updates")
updates_manager.apply_all
end
updated
end

protected

# Instantiates an UpdatesManager to be used by the client
#
# The manager is 'memoized'.
Expand All @@ -75,30 +101,53 @@ def self_update_enabled?
log.info("self-update was disabled through Linuxrc")
false
else
!self_update_url.nil?
!self_update_urls.empty?
end
end

# Return the self-update URL
# Return the self-update URLs
#
# @return [URI] self-update URL
# @return [Array<URI>] self-update URLs
#
# @see #custom_self_update_url
# @see #default_self_update_url
def self_update_urls
return @self_update_urls unless @self_update_urls.nil?
@self_update_urls = Array(custom_self_update_url)
@self_update_urls = default_self_update_urls if @self_update_urls.empty?
log.info("self-update URLs are #{@self_update_urls}")
@self_update_urls
end

# Return the default self-update URLs
#
# A default URL can be specified via SCC/SMT servers or in the control.xml file.
#
# @return [Array<URI>] self-update URLs
def default_self_update_urls
return @default_self_update_urls unless @default_self_update_urls.nil?
@default_self_update_urls = self_update_url_from_connect
return @default_self_update_urls unless @default_self_update_urls.empty?
@default_self_update_urls = Array(self_update_url_from_control)
end

# Return the custom self-update URL
#
# A custom URL can be specified via Linuxrc or in an AutoYaST profile.
# Only 1 custom self-update URL can be specified.
#
# @return [URI] self-update URL
# @see #self_update_url_from_linuxrc
# @see #self_update_url_from_control
# @see #self_update_url_from_profile
# @see #self_update_url_from_connect
def self_update_url
return @url unless @url.nil?
@url = self_update_url_from_linuxrc || self_update_url_from_profile ||
self_update_url_from_connect || self_update_url_from_control
log.info("self-update URL is #{@url}")
@url
def custom_self_update_url
@custom_self_update_url ||= self_update_url_from_linuxrc || self_update_url_from_profile
end

# Return the self-update URL from SMT servers
# Return the self-update URLs from SCC/SMT server
#
# Return nil if yast2-registration or SUSEConnect are not available
# (for instance in openSUSE).
# Return an empty array if yast2-registration or SUSEConnect are
# not available (for instance in openSUSE). More than 1 URLs can
# be specified.
#
# @return [URI,nil] self-update URL. nil if no URL was found.
def self_update_url_from_connect
Expand All @@ -107,13 +156,20 @@ def self_update_url_from_connect
require "suse/connect"
base_product = Registration::SwMgmt.base_product_to_register
product = Registration::SwMgmt.remote_product(base_product)
update = SUSE::Connect::YaST.list_installer_updates(product,
url: Registration::UrlHelpers.registration_url).first
log.info("self-update repository for product '#{base_product}' is #{update}")
update ? URI(update.url) : nil
updates = SUSE::Connect::YaST.list_installer_updates(product,
url: Registration::UrlHelpers.registration_url)
log.info("self-update repository for product '#{base_product}' are #{updates}")
updates.map { |u| URI(u.url) }
rescue LoadError
log.info "yast2-registration or SUSEConnect are not available"
nil
[]
end

# Return the self-update URL according to product's control file
#
# @return [URI,nil] self-update URL. nil if no URL was set in control file.
def self_update_url_from_control
get_url_from(ProductFeatures.GetStringFeature("globals", "self_update_url"))
end

# Return the self-update URL according to Linuxrc
Expand All @@ -123,12 +179,6 @@ def self_update_url_from_linuxrc
get_url_from(Linuxrc.InstallInf("SelfUpdate"))
end

# Return the self-update URL according to product's control file
#
def self_update_url_from_control
get_url_from(ProductFeatures.GetStringFeature("globals", "self_update_url"))
end

# Return the self-update URL from the AutoYaST profile
# @return [URI,nil] the self-update URL, nil if not running in AutoYaST mode
# or when the URL is not defined in the profile
Expand Down Expand Up @@ -180,67 +230,53 @@ def update_flag_file
File.join(Directory.vardir, UPDATED_FLAG_FILENAME)
end

# Tries to update the installer
#
# It also shows feedback to the user in case of error.
# Add a repository to the updates manager
#
# Errors handling:
#
# * A repository is not found: warn the user if she/he is using
# a custom URL.
# * Could not fetch update from repository: report the user about
# this error.
# * Repository could not be probed: suggest checking network
# configuration if URL has a REMOTE_SCHEME.
#
# @return [Boolean] true if installer was updated; false otherwise.
def update_installer
log.info("Adding update from #{self_update_url}")
updates_manager.add_repository(self_update_url)
updated = updates_manager.repositories?
if updated
log.info("Applying installer updates")
updates_manager.apply_all
end
updated

rescue ::Installation::UpdatesManager::NotValidRepo
if !using_default_url?
# @param url [URI] Repository URL
# @return [Boolean] true if the repository was added; false otherwise.
def add_repository(url)
log.info("Adding update from #{url}")
updates_manager.add_repository(url)

rescue ::Installation::UpdatesManager::NotValidRepo => e
if !default_url?(e.uri)
# TRANSLATORS: %s is an URL
Report.Error(format(_("A valid update could not be found at\n%s.\n\n"), self_update_url))
Report.Error(format(_("A valid update could not be found at\n%s.\n\n"), e.uri))
end
false

rescue ::Installation::UpdatesManager::CouldNotFetchUpdateFromRepo
rescue ::Installation::UpdatesManager::CouldNotFetchUpdateFromRepo => e
# TRANSLATORS: %s is an URL
Report.Error(format(_("Could not fetch update from\n%s.\n\n"), self_update_url))
Report.Error(format(_("Could not fetch update from\n%s.\n\n"), e.uri))
false

rescue ::Installation::UpdatesManager::CouldNotProbeRepo
if Mode.auto
Report.Warning(could_not_probe_repo_msg)
elsif remote_self_update_url? && configure_network?
elsif remote_url?(e.uri) && configure_network?(e.uri)
retry
end
false
end

# Determine whether the URL is remote
#
# @param url [URI] URL to check
# @return [Boolean] true if it's considered remote; false otherwise.
def remote_self_update_url?
REMOTE_SCHEMES.include?(self_update_url.scheme)
def remote_url?(url)
REMOTE_SCHEMES.include?(url.scheme)
end

# Launch the network configuration client on users' demand
#
# Ask the user about checking network configuration. If she/he accepts,
# the `inst_lan` client will be launched.
#
# @param url [URI] URL to show in the message
# @return [Boolean] true if the network configuration client was launched;
# false if the network is not configured.
def configure_network?
msg = could_not_probe_repo_msg +
def configure_network?(url)
msg = could_not_probe_repo_msg(url) +
_("\nWould you like to check your network configuration\n" \
"and try installing the updates again?")

Expand Down Expand Up @@ -272,16 +308,17 @@ def try_to_update?
# Determines whether the given URL is equal to the default one
#
# @return [Boolean] true if it's the default URL; false otherwise.
def using_default_url?
self_update_url_from_control == self_update_url
def default_url?(uri)
default_self_update_urls.include?(uri)
end

# Return a message to be shown when the updates repo could not be probed
#
# @param [URI,String] Repository URI
# @return [String] Message including the repository URL
#
# @see #self_update_url
def could_not_probe_repo_msg
def could_not_probe_repo_msg(url)
# Note: the proxy cannot be configured in the YaST installer yet,
# it needs to be set via the "proxy" boot option.
# TRANSLATORS: %s is an URL
Expand All @@ -291,7 +328,7 @@ def could_not_probe_repo_msg
"However, some potentially important bug fixes might be missing.\n" \
"\n" \
"If you need a proxy server to access the update repository\n" \
"then use the \"proxy\" boot parameter.\n"), self_update_url)
"then use the \"proxy\" boot parameter.\n"), url.to_s)
end
end
end
26 changes: 20 additions & 6 deletions src/lib/installation/updates_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,29 @@ class UpdatesManager
# @return [Array<DriverUpdate>] Driver updates found in inst-sys
attr_reader :driver_updates

# Base exception to be used for repository problems
class RepoError < StandardError
# @return [URI] Repository URI
attr_reader :uri

# Constructor
#
# @param uri [URI] Repository URI
def initialize(uri)
super()
@uri = uri
end
end

# The URL was found but a valid repo is not there.
class NotValidRepo < StandardError; end
class NotValidRepo < RepoError; end

# The update could not be fetched (missing packages, broken
# repository, etc.).
class CouldNotFetchUpdateFromRepo < StandardError; end
class CouldNotFetchUpdateFromRepo < RepoError; end

# Repo is unreachable (name solving issues, etc.).
class CouldNotProbeRepo < StandardError; end
class CouldNotProbeRepo < RepoError; end

DRIVER_UPDATES_PATHS = [Pathname("/update"), Pathname("/download")].freeze

Expand Down Expand Up @@ -90,13 +104,13 @@ def add_repository(uri)
has_packages
rescue Installation::UpdateRepository::NotValidRepo
log.warn("Update repository at #{uri} could not be found")
raise NotValidRepo
raise NotValidRepo.new(uri)
rescue Installation::UpdateRepository::FetchError
log.error("Update repository at #{uri} was found but update could not be fetched")
raise CouldNotFetchUpdateFromRepo
raise CouldNotFetchUpdateFromRepo.new(uri)
rescue Installation::UpdateRepository::CouldNotProbeRepo
log.error("Update repository at #{uri} could not be read")
raise CouldNotProbeRepo
raise CouldNotProbeRepo.new(uri)
end

# Applies all the updates
Expand Down
Loading

0 comments on commit 5fe00cd

Please sign in to comment.