def remove_apt_config(self): """Remove any repository apt configuration files.""" series = util.get_platform_info()['series'] repo_filename = self.repo_list_file_tmpl.format( name=self.name, series=series) keyring_file = os.path.join(apt.APT_KEYS_DIR, self.repo_key_file) entitlement = self.cfg.read_cache( 'machine-access-%s' % self.name).get('entitlement', {}) access_directives = entitlement.get('directives', {}) repo_url = access_directives.get('aptURL', self.repo_url) if not repo_url: repo_url = self.repo_url if self.disable_apt_auth_only: # We only remove the repo from the apt auth file, because ESM # is a special-case: we want to be able to report on the # available ESM updates even when it's disabled apt.remove_repo_from_apt_auth_file(repo_url) apt.restore_commented_apt_list_file(repo_filename) else: apt.remove_auth_apt_repo(repo_filename, repo_url, keyring_file) apt.remove_apt_list_files(repo_url, series) if self.repo_pin_priority: repo_pref_file = self.repo_pref_file_tmpl.format( name=self.name, series=series) if self.repo_pin_priority == 'never': # Disable the repo with a pinning file apt.add_ppa_pinning( repo_pref_file, repo_url, self.origin, self.repo_pin_priority) elif os.path.exists(repo_pref_file): os.unlink(repo_pref_file)
def enable(self): """Enable specific entitlement. @return: True on success, False otherwise. """ if not self.can_enable(): return False series = util.get_platform_info('series') repo_filename = self.repo_list_file_tmpl.format(name=self.name, series=series) resource_cfg = self.cfg.entitlements.get(self.name) directives = resource_cfg['entitlement'].get('directives', {}) token = resource_cfg.get('resourceToken') if not token: logging.debug( 'No specific resourceToken present. Using machine token' ' as %s credentials', self.title) token = self.cfg.machine_token['machineSecret'] ppa_fingerprint = directives.get('aptKey') if ppa_fingerprint: keyring_file = None else: keyring_file = os.path.join(apt.KEYRINGS_DIR, self.repo_key_file) repo_url = directives.get('aptURL') if not repo_url: repo_url = self.repo_url try: apt.add_auth_apt_repo(repo_filename, repo_url, token, keyring_file, ppa_fingerprint) except apt.InvalidAPTCredentialsError as e: logging.error(str(e)) return False if self.repo_pin_priority: repo_pref_file = self.repo_pref_file_tmpl.format(name=self.name, series=series) apt.add_ppa_pinning(repo_pref_file, repo_url, self.repo_pin_priority) if not os.path.exists(apt.APT_METHOD_HTTPS_FILE): util.subp(['apt-get', 'install', 'apt-transport-https'], capture=True) if not os.path.exists(apt.CA_CERTIFICATES_FILE): util.subp(['apt-get', 'install', 'ca-certificates'], capture=True) try: util.subp(['apt-get', 'update'], capture=True) if self.packages: print('Installing {title} packages' ' (this may take a while)'.format(title=self.title)) util.subp(['apt-get', 'install'] + self.packages) except util.ProcessExecutionError: self.disable(silent=True, force=True) logging.error( status.MESSAGE_ENABLED_FAILED_TMPL.format(title=self.title)) return False print(status.MESSAGE_ENABLED_TMPL.format(title=self.title)) return True
def remove_apt_config(self, run_apt_update: bool = True, silent: bool = False): """Remove any repository apt configuration files. :param run_apt_update: If after removing the apt update command after removing the apt files. """ series = util.get_platform_info()["series"] repo_filename = self.repo_list_file_tmpl.format(name=self.name) entitlement = self.cfg.entitlements[self.name].get("entitlement", {}) access_directives = entitlement.get("directives", {}) repo_url = access_directives.get("aptURL") if not repo_url: raise exceptions.MissingAptURLDirective(self.name) if self.disable_apt_auth_only: # We only remove the repo from the apt auth file, because # UA Infra: ESM is a special-case: we want to be able to report on # the available UA Infra: ESM updates even when it's disabled apt.remove_repo_from_apt_auth_file(repo_url) apt.restore_commented_apt_list_file(repo_filename) else: apt.remove_auth_apt_repo(repo_filename, repo_url, self.repo_key_file) apt.remove_apt_list_files(repo_url, series) if self.repo_pin_priority: repo_pref_file = self.repo_pref_file_tmpl.format(name=self.name) if self.repo_pin_priority == "never": # Disable the repo with a pinning file apt.add_ppa_pinning( repo_pref_file, repo_url, self.origin, self.repo_pin_priority, ) elif os.path.exists(repo_pref_file): os.unlink(repo_pref_file) if run_apt_update: if not silent: event.info(messages.APT_UPDATING_LISTS) apt.run_apt_update_command()
def test_write_apt_pin_file_to_apt_preferences(self, m_platform, tmpdir): """Write proper apt pin file to specified apt_preference_file.""" m_platform.return_value = 'xenial' pref_file = tmpdir.join('preffile').strpath assert None is add_ppa_pinning( pref_file, repo_url='http://fakerepo', origin='MYORIG', priority=1003) expected_pref = dedent('''\ Package: * Pin: release o=MYORIG, n=xenial Pin-Priority: 1003\n''') assert expected_pref == util.load_file(pref_file)
def remove_apt_config(self): """Remove any repository apt configuration files.""" series = util.get_platform_info()["series"] repo_filename = self.repo_list_file_tmpl.format( name=self.name, series=series ) entitlement = self.cfg.entitlements[self.name].get("entitlement", {}) access_directives = entitlement.get("directives", {}) repo_url = access_directives.get("aptURL") if not repo_url: raise exceptions.MissingAptURLDirective(self.name) if self.disable_apt_auth_only: # We only remove the repo from the apt auth file, because ESM Infra # is a special-case: we want to be able to report on the # available ESM Infra updates even when it's disabled apt.remove_repo_from_apt_auth_file(repo_url) apt.restore_commented_apt_list_file(repo_filename) else: apt.remove_auth_apt_repo( repo_filename, repo_url, self.repo_key_file ) apt.remove_apt_list_files(repo_url, series) if self.repo_pin_priority: repo_pref_file = self.repo_pref_file_tmpl.format( name=self.name, series=series ) if self.repo_pin_priority == "never": # Disable the repo with a pinning file apt.add_ppa_pinning( repo_pref_file, repo_url, self.origin, self.repo_pin_priority, ) elif os.path.exists(repo_pref_file): os.unlink(repo_pref_file) print(status.MESSAGE_APT_UPDATING_LISTS) apt.run_apt_command( ["apt-get", "update"], status.MESSAGE_APT_UPDATE_FAILED )
def test_write_apt_pin_file_to_apt_preferences(self, m_platform, tmpdir): """Write proper apt pin file to specified apt_preference_file.""" m_platform.return_value = {"series": "xenial"} pref_file = tmpdir.join("preffile").strpath assert None is add_ppa_pinning( pref_file, repo_url="http://fakerepo", origin="MYORIG", priority=1003, ) expected_pref = dedent("""\ Package: * Pin: release o=MYORIG, n=xenial Pin-Priority: 1003\n""") assert expected_pref == util.load_file(pref_file)
def setup_apt_config(self) -> None: """Setup apt config based on the resourceToken and directives. :raise UserFacingError: on failure to setup any aspect of this apt configuration """ series = util.get_platform_info()["series"] repo_filename = self.repo_list_file_tmpl.format( name=self.name, series=series ) resource_cfg = self.cfg.entitlements.get(self.name) directives = resource_cfg["entitlement"].get("directives", {}) token = resource_cfg.get("resourceToken") if not token: logging.debug( "No specific resourceToken present. Using machine token" " as %s credentials", self.title, ) token = self.cfg.machine_token["machineToken"] aptKey = directives.get("aptKey") if not aptKey: raise exceptions.UserFacingError( "Ubuntu Advantage server provided no aptKey directive for" " {}.".format(self.name) ) repo_url = directives.get("aptURL") if not repo_url: raise exceptions.MissingAptURLDirective(self.name) repo_suites = directives.get("suites") if not repo_suites: raise exceptions.UserFacingError( "Empty {} apt suites directive from {}".format( self.name, self.cfg.contract_url ) ) if self.repo_pin_priority: if not self.origin: raise exceptions.UserFacingError( "Cannot setup apt pin. Empty apt repo origin value '{}'.\n" "{}".format( self.origin, status.MESSAGE_ENABLED_FAILED_TMPL.format( title=self.title ), ) ) repo_pref_file = self.repo_pref_file_tmpl.format( name=self.name, series=series ) if self.repo_pin_priority != "never": apt.add_ppa_pinning( repo_pref_file, repo_url, self.origin, self.repo_pin_priority, ) elif os.path.exists(repo_pref_file): os.unlink(repo_pref_file) # Remove disabling apt pref file prerequisite_pkgs = [] if not os.path.exists(apt.APT_METHOD_HTTPS_FILE): prerequisite_pkgs.append("apt-transport-https") if not os.path.exists(apt.CA_CERTIFICATES_FILE): prerequisite_pkgs.append("ca-certificates") if prerequisite_pkgs: print( "Installing prerequisites: {}".format( ", ".join(prerequisite_pkgs) ) ) try: apt.run_apt_command( ["apt-get", "install", "--assume-yes"] + prerequisite_pkgs, status.MESSAGE_APT_INSTALL_FAILED, ) except exceptions.UserFacingError: self.remove_apt_config() raise apt.add_auth_apt_repo( repo_filename, repo_url, token, repo_suites, self.repo_key_file ) # Run apt-update on any repo-entitlement enable because the machine # probably wants access to the repo that was just enabled. # Side-effect is that apt policy will now report the repo as accessible # which allows ua status to report correct info print(status.MESSAGE_APT_UPDATING_LISTS) try: apt.run_apt_command( ["apt-get", "update"], status.MESSAGE_APT_UPDATE_FAILED ) except exceptions.UserFacingError: self.remove_apt_config() raise
def enable(self): """Enable specific entitlement. @return: True on success, False otherwise. """ if not self.can_enable(): return False series = util.get_platform_info('series') repo_filename = self.repo_list_file_tmpl.format( name=self.name, series=series) resource_cfg = self.cfg.entitlements.get(self.name) directives = resource_cfg['entitlement'].get('directives', {}) token = resource_cfg.get('resourceToken') if not token: logging.debug( 'No specific resourceToken present. Using machine token' ' as %s credentials', self.title) token = self.cfg.machine_token['machineToken'] ppa_fingerprint = directives.get('aptKey') if ppa_fingerprint: keyring_file = None else: keyring_file = os.path.join(apt.KEYRINGS_DIR, self.repo_key_file) repo_url = directives.get('aptURL') if not repo_url: repo_url = self.repo_url if self.repo_pin_priority: if not self.origin: logging.error( "Cannot setup apt pin. Empty apt repo origin value '%s'." % self.origin) logging.error( status.MESSAGE_ENABLED_FAILED_TMPL.format( title=self.title)) return False repo_pref_file = self.repo_pref_file_tmpl.format( name=self.name, series=series) apt.add_ppa_pinning( repo_pref_file, repo_url, self.origin, self.repo_pin_priority) prerequisite_pkgs = [] if not os.path.exists(apt.APT_METHOD_HTTPS_FILE): prerequisite_pkgs.append('apt-transport-https') if not os.path.exists(apt.CA_CERTIFICATES_FILE): prerequisite_pkgs.append('ca-certificates') if prerequisite_pkgs: print('Installing prerequisites: {}'.format( ', '.join(prerequisite_pkgs))) try: util.subp( ['apt-get', 'install', '--assume-yes'] + prerequisite_pkgs, capture=True) except util.ProcessExecutionError as e: logging.error(str(e)) return False try: apt.add_auth_apt_repo( repo_filename, repo_url, token, keyring_file, ppa_fingerprint, pockets=self.repo_pockets) except apt.InvalidAPTCredentialsError as e: logging.error(str(e)) return False if self.packages: try: print('Updating package lists ...') util.subp(['apt-get', 'update'], capture=True) print( 'Installing {title} packages ...'.format(title=self.title)) util.subp( ['apt-get', 'install', '--assume-yes'] + self.packages, capture=True) except util.ProcessExecutionError: self.disable(silent=True, force=True) logging.error( status.MESSAGE_ENABLED_FAILED_TMPL.format( title=self.title)) return False print(status.MESSAGE_ENABLED_TMPL.format(title=self.title)) for msg in self.messaging.get('post_enable', []): print(msg) return True
def setup_apt_config(self, silent: bool = False) -> None: """Setup apt config based on the resourceToken and directives. Also sets up apt proxy if necessary. :raise UserFacingError: on failure to setup any aspect of this apt configuration """ http_proxy = None # type: Optional[str] https_proxy = None # type: Optional[str] scope = None # type: Optional[apt.AptProxyScope] if self.cfg.global_apt_http_proxy or self.cfg.global_apt_https_proxy: http_proxy = util.validate_proxy( "http", self.cfg.global_apt_http_proxy, util.PROXY_VALIDATION_APT_HTTP_URL, ) https_proxy = util.validate_proxy( "https", self.cfg.global_apt_https_proxy, util.PROXY_VALIDATION_APT_HTTPS_URL, ) scope = apt.AptProxyScope.GLOBAL elif self.cfg.ua_apt_http_proxy or self.cfg.ua_apt_https_proxy: http_proxy = util.validate_proxy( "http", self.cfg.ua_apt_http_proxy, util.PROXY_VALIDATION_APT_HTTP_URL, ) https_proxy = util.validate_proxy( "https", self.cfg.ua_apt_https_proxy, util.PROXY_VALIDATION_APT_HTTPS_URL, ) scope = apt.AptProxyScope.UACLIENT apt.setup_apt_proxy(http_proxy=http_proxy, https_proxy=https_proxy, proxy_scope=scope) repo_filename = self.repo_list_file_tmpl.format(name=self.name) resource_cfg = self.cfg.entitlements.get(self.name) directives = resource_cfg["entitlement"].get("directives", {}) obligations = resource_cfg["entitlement"].get("obligations", {}) token = resource_cfg.get("resourceToken") if not token: machine_token = self.cfg.machine_token["machineToken"] if not obligations.get("enableByDefault"): # services that are not enableByDefault need to obtain specific # resource access for tokens. We want to refresh this every # enable call because it is not refreshed by `ua refresh`. client = contract.UAContractClient(self.cfg) machine_access = client.request_resource_machine_access( machine_token, self.name) if machine_access: token = machine_access.get("resourceToken") if not token: token = machine_token logging.warning( "No resourceToken present in contract for service %s." " Using machine token as credentials", self.title, ) aptKey = directives.get("aptKey") if not aptKey: raise exceptions.UserFacingError( "Ubuntu Advantage server provided no aptKey directive for" " {}.".format(self.name)) repo_url = directives.get("aptURL") if not repo_url: raise exceptions.MissingAptURLDirective(self.name) repo_suites = directives.get("suites") if not repo_suites: raise exceptions.UserFacingError( "Empty {} apt suites directive from {}".format( self.name, self.cfg.contract_url)) if self.repo_pin_priority: if not self.origin: raise exceptions.UserFacingError( "Cannot setup apt pin. Empty apt repo origin value '{}'.\n" "{}".format( self.origin, messages.ENABLED_FAILED.format(title=self.title).msg, )) repo_pref_file = self.repo_pref_file_tmpl.format(name=self.name) if self.repo_pin_priority != "never": apt.add_ppa_pinning( repo_pref_file, repo_url, self.origin, self.repo_pin_priority, ) elif os.path.exists(repo_pref_file): os.unlink(repo_pref_file) # Remove disabling apt pref file prerequisite_pkgs = [] if not os.path.exists(apt.APT_METHOD_HTTPS_FILE): prerequisite_pkgs.append("apt-transport-https") if not os.path.exists(apt.CA_CERTIFICATES_FILE): prerequisite_pkgs.append("ca-certificates") if prerequisite_pkgs: if not silent: event.info("Installing prerequisites: {}".format( ", ".join(prerequisite_pkgs))) try: apt.run_apt_install_command(packages=prerequisite_pkgs) except exceptions.UserFacingError: self.remove_apt_config() raise apt.add_auth_apt_repo(repo_filename, repo_url, token, repo_suites, self.repo_key_file) # Run apt-update on any repo-entitlement enable because the machine # probably wants access to the repo that was just enabled. # Side-effect is that apt policy will now report the repo as accessible # which allows ua status to report correct info if not silent: event.info(messages.APT_UPDATING_LISTS) try: apt.run_apt_update_command() except exceptions.UserFacingError: self.remove_apt_config(run_apt_update=False) raise
def setup_apt_config(self) -> None: """Setup apt config based on the resourceToken and directives. :raise UserFacingError: on failure to setup any aspect of this apt configuration """ series = util.get_platform_info()['series'] repo_filename = self.repo_list_file_tmpl.format( name=self.name, series=series) resource_cfg = self.cfg.entitlements.get(self.name) directives = resource_cfg['entitlement'].get('directives', {}) token = resource_cfg.get('resourceToken') if not token: logging.debug( 'No specific resourceToken present. Using machine token' ' as %s credentials', self.title) token = self.cfg.machine_token['machineToken'] if directives.get('aptKey'): logging.debug( "Ignoring aptKey directive '%s'", directives.get('aptKey')) keyring_file = os.path.join(apt.KEYRINGS_DIR, self.repo_key_file) repo_url = directives.get('aptURL') if not repo_url: repo_url = self.repo_url repo_suites = directives.get('suites') if not repo_suites: raise exceptions.UserFacingError( 'Empty %s apt suites directive from %s' % (self.name, self.cfg.contract_url)) if self.repo_pin_priority: if not self.origin: raise exceptions.UserFacingError( "Cannot setup apt pin. Empty apt repo origin value '%s'.\n" "%s" % (self.origin, status.MESSAGE_ENABLED_FAILED_TMPL.format( title=self.title))) repo_pref_file = self.repo_pref_file_tmpl.format( name=self.name, series=series) if self.repo_pin_priority != 'never': apt.add_ppa_pinning( repo_pref_file, repo_url, self.origin, self.repo_pin_priority) elif os.path.exists(repo_pref_file): os.unlink(repo_pref_file) # Remove disabling apt pref file prerequisite_pkgs = [] if not os.path.exists(apt.APT_METHOD_HTTPS_FILE): prerequisite_pkgs.append('apt-transport-https') if not os.path.exists(apt.CA_CERTIFICATES_FILE): prerequisite_pkgs.append('ca-certificates') if prerequisite_pkgs: print('Installing prerequisites: {}'.format( ', '.join(prerequisite_pkgs))) try: apt.run_apt_command( ['apt-get', 'install', '--assume-yes'] + prerequisite_pkgs, status.MESSAGE_APT_INSTALL_FAILED) except exceptions.UserFacingError: self.remove_apt_config() raise apt.add_auth_apt_repo(repo_filename, repo_url, token, repo_suites, keyring_file) # Run apt-update on any repo-entitlement enable because the machine # probably wants access to the repo that was just enabled. # Side-effect is that apt policy will now report the repo as accessible # which allows ua status to report correct info print('Updating package lists') try: apt.run_apt_command( ['apt-get', 'update'], status.MESSAGE_APT_UPDATE_FAILED) except exceptions.UserFacingError: self.remove_apt_config() raise
def setup_apt_config(self): series = util.get_platform_info('series') repo_filename = self.repo_list_file_tmpl.format(name=self.name, series=series) resource_cfg = self.cfg.entitlements.get(self.name) directives = resource_cfg['entitlement'].get('directives', {}) token = resource_cfg.get('resourceToken') if not token: logging.debug( 'No specific resourceToken present. Using machine token' ' as %s credentials', self.title) token = self.cfg.machine_token['machineToken'] if directives.get('aptKey'): logging.debug("Ignoring aptKey directive '%s'", directives.get('aptKey')) keyring_file = os.path.join(apt.KEYRINGS_DIR, self.repo_key_file) repo_url = directives.get('aptURL') if not repo_url: repo_url = self.repo_url repo_suites = directives.get('suites') if not repo_suites: logging.error('Empty %s apt suites directive from %s', self.name, self.cfg.contract_url) return False if self.repo_pin_priority: if not self.origin: logging.error( "Cannot setup apt pin. Empty apt repo origin value '%s'." % self.origin) logging.error( status.MESSAGE_ENABLED_FAILED_TMPL.format( title=self.title)) return False repo_pref_file = self.repo_pref_file_tmpl.format(name=self.name, series=series) apt.add_ppa_pinning(repo_pref_file, repo_url, self.origin, self.repo_pin_priority) prerequisite_pkgs = [] if not os.path.exists(apt.APT_METHOD_HTTPS_FILE): prerequisite_pkgs.append('apt-transport-https') if not os.path.exists(apt.CA_CERTIFICATES_FILE): prerequisite_pkgs.append('ca-certificates') if prerequisite_pkgs: print('Installing prerequisites: {}'.format( ', '.join(prerequisite_pkgs))) try: util.subp(['apt-get', 'install', '--assume-yes'] + prerequisite_pkgs, capture=True) except util.ProcessExecutionError as e: logging.error(str(e)) return False try: apt.add_auth_apt_repo(repo_filename, repo_url, token, repo_suites, keyring_file) except apt.InvalidAPTCredentialsError as e: logging.error(str(e)) return False # Run apt-update on any repo-entitlement enable because the machine # probably wants access to the repo that was just enabled. # Side-effect is that apt policy will new report the repo as accessible # which allows ua status to report correct info print('Updating package lists ...') util.subp(['apt-get', 'update'], capture=True) return True