Ejemplo n.º 1
0
 def _create_new_repo(self, args):
     if not args.ini or not os.path.exists(args.ini):
         raise Abort('An ini file is needed for new apps')
     app = App.from_ini(args.ini)
     if not app:
         raise Abort('Cannot continue with flawed ini file')
     if args.component_id:
         component_id = args.component_id
     else:
         component_id = '%s_%s' % (app.id, date.today().strftime('%Y%m%d'))
     return self._build_repo_dir(app, component_id, args.path,
                                 args.ucs_version)
Ejemplo n.º 2
0
 def _upgrade_release(self, app, release):
     process = self._execute_container_script(app,
                                              'update_release',
                                              _credentials=False,
                                              release=release)
     if not process or process.returncode != 0:
         raise Abort('Release upgrade script failed')
Ejemplo n.º 3
0
	def _register_database(self, app):
		database_connector = DatabaseConnector.get_connector(app)
		if database_connector:
			try:
				database_connector.create_database()
			except DatabaseError as exc:
				raise Abort(str(exc))
Ejemplo n.º 4
0
 def set_ini_value(self, section, attr, value, parser):
     if not re.match('^[a-zA-Z0-9_]+$', attr):
         raise Abort('May not use %s as attribute' % attr)
     try:
         items = parser.items(section)
     except NoSectionError:
         items = []
     for name, old_value in items:
         if attr.lower() == name.lower():
             if attr != name:
                 self.warn('Using %s instead of %s as attribute' %
                           (name, attr))
                 attr = name
             self.log('%s: Overwriting %r' % (attr, old_value))
     self.debug('Setting [%s]%s=%r' % (section, attr, value))
     if value is None:
         try:
             parser.remove_option(section, attr)
         except NoSectionError:
             pass
     else:
         try:
             parser.add_section(section)
         except DuplicateSectionError:
             pass
         except ValueError:
             section = 'DEFAULT'
         parser.set(section, attr, value)
Ejemplo n.º 5
0
 def _docker_upgrade_mode(self, app):
     mode = None
     detail = None
     if self.old_app.docker and app.plugin_of:
         if app > self.old_app:
             mode, detail = 'app', app.version
         return mode, detail
     if not self.old_app.docker:
         return 'docker', None
     if not Start.call(app=self.old_app):
         raise Abort(
             'Could not start the app container. It needs to be running to be upgraded!'
         )
     mode = self._execute_container_script(
         self.old_app, 'update_available', _credentials=False,
         _output=True) or ''
     mode = mode.strip()
     if mode.startswith('release:'):
         mode, detail = 'release', mode[8:].strip()
     if mode not in ['packages', 'release']:
         # packages and release first!
         if app > self.old_app:
             mode, detail = 'app', app.version
         if self.old_app.get_docker_image_name(
         ) not in app.get_docker_images():
             mode, detail = 'image', app.get_docker_image_name()
     return mode, detail
Ejemplo n.º 6
0
 def main(self, args):
     if args.meta:
         ini_file = args.app.get_cache_file('meta')
     else:
         ini_file = args.app.get_ini_file()
     parser = read_ini_file(ini_file, CaseSensitiveConfigParser)
     for section, attr, value in args.attrs:
         attribute = args.app.get_attr(underscore(attr))
         self.process(args.app, attribute, section, camelcase(attr), value,
                      parser)
     self.log('Rewriting %s' % ini_file)
     with NamedTemporaryFile('w+b') as tmp_ini_file:
         parser.write(tmp_ini_file)
         tmp_ini_file.flush()
         if not args.meta:
             for locale in ['en', 'de']:
                 new_app = App.from_ini(tmp_ini_file.name,
                                        locale=locale,
                                        cache=args.app.get_app_cache_obj())
                 if new_app is None:
                     raise Abort(
                         'ini file would be malformed. Not saving attributes!'
                     )
         shutil.copy2(tmp_ini_file.name, ini_file)
         os.chmod(ini_file, 0o644)
         args.app.get_app_cache_obj().clear_cache()
Ejemplo n.º 7
0
 def _remove_app(self, app, args):
     if not app.docker:
         super(Remove, self)._remove_app(app, args)
     else:
         if app.plugin_of:
             raise Abort('Uninstallation of a plugin is not supported!')
         else:
             self._remove_docker_container(app, args)
Ejemplo n.º 8
0
 def _upgrade_app(self, app, args):
     process = self._execute_container_script(app, 'update_app_version',
                                              args)
     if not process or process.returncode != 0:
         raise Abort('App upgrade script failed')
     self._register_app(app, args)
     self._call_join_script(app, args)
     self.old_app = app
Ejemplo n.º 9
0
 def verify(self):
     if ucr_is_false('appcenter/index/verify'):
         return
     try:
         verify(self.app, self.image)
     except Exception as exc:
         self.logger.fatal(str(exc))
         raise Abort()
Ejemplo n.º 10
0
 def _remove_docker_container(self, app, args):
     if args.backup:
         if self._backup_container(app, backup_data='move') is False:
             raise Abort('Could not backup container!')
     docker = self._get_docker(app)
     if docker.container:
         Stop.call(app=app)
         docker.stop()
         docker.rm()
Ejemplo n.º 11
0
 def main(self, args):
     docker = self._get_docker(args.app)
     docker_exec = ['docker', 'exec']
     commands = args.commands[:]
     if not commands:
         commands = shlex.split(args.app.docker_shell_command)
         args.interactive = True
         args.tty = True
     if args.interactive:
         docker_exec.append('-i')
     if args.tty:
         docker_exec.append('-t')
     if not commands:
         raise Abort('Cannot run command: No command specified')
     if not app_is_running(args.app):
         raise Abort(
             'Cannot run command: %s is not running in a container' %
             args.app.id)
     self.debug('Calling %s' % commands[0])
     return subprocess.call(docker_exec + [docker.container] + commands)
Ejemplo n.º 12
0
 def _setup_docker_image(self, app, args):
     self._execute_container_script(app,
                                    'restore_data_before_setup',
                                    _credentials=False)
     if app.docker_script_setup:
         process = self._execute_container_script(app, 'setup', args)
         if not process or process.returncode != 0:
             raise Abort(_('Setup script failed!'))
     self._execute_container_script(app,
                                    'restore_data_after_setup',
                                    _credentials=False)
Ejemplo n.º 13
0
	def _load_index_json(self, app_cache):
		index_json_gz_filename = os.path.join(app_cache.get_cache_dir(), '.index.json.gz')
		if not ucr_is_false('appcenter/index/verify'):
			detached_sig_path = index_json_gz_filename + '.gpg'
			(rc, gpg_error) = gpg_verify(index_json_gz_filename, detached_sig_path)
			if rc:
				if gpg_error:
					self.fatal(gpg_error)
				raise Abort('Signature verification for %s failed' % index_json_gz_filename)
		with gzip_open(index_json_gz_filename, 'rb') as fgzip:
			content = fgzip.read()
			return loads(content)
Ejemplo n.º 14
0
	def _register_attributes(self, app, args):
		# FIXME: there is no better lib function than this snippet
		schema_file = app.get_share_file('schema')
		if os.path.exists(schema_file):
			self.log('Registering schema %s' % schema_file)
			lo, pos = self._get_ldap_connection(args)
			with self._get_password_file(args) as password_file:
				create_recursive_container('cn=ldapschema,cn=univention,%s' % ucr_get('ldap/base'), lo, pos)
				schema_obj = UniventionLDAPSchema(ucr_instance())
				userdn = self._get_userdn(args)
				udm_passthrough_options = ['--binddn', userdn, '--bindpwdfile', password_file]
				opts = Values()
				opts.packagename = 'appcenter-app-%s' % app.id
				opts.packageversion = app.version
				opts.ucsversionstart = None
				opts.ucsversionend = None
				os.environ['UNIVENTION_APP_IDENTIFIER'] = app.id
				try:
					schema_obj.register(schema_file, opts, udm_passthrough_options)
				except SystemExit as exc:
					if exc.code == 4:
						self.warn('A newer version of %s has already been registered. Skipping...' % schema_file)
					else:
						raise Abort('Registration of schema extension failed (Code: %s)' % exc.code)
				else:
					if not schema_obj.wait_for_activation():
						raise Abort('Registering schema file %s failed' % schema_file)
				finally:
					del os.environ['UNIVENTION_APP_IDENTIFIER']

				# and this is what should be there after one line of lib.register_schema(schema_file)
				app = app.get_app_cache_obj().copy(locale='en').find_by_component_id(app.component_id)
				attributes, __ = get_extended_attributes(app)
				if attributes:
					for i, attribute in enumerate(attributes):
						self.log('Registering attribute %s' % attribute.name)
						create_extended_attribute(attribute, app, i + 1, lo, pos)
Ejemplo n.º 15
0
 def _install_only_master_packages_remotely(self, app, host, is_master,
                                            args):
     if args.install_master_packages_remotely:
         self.log('Installing some packages of %s on %s' % (app.id, host))
     else:
         self.warn(
             'Not installing packages on %s. Please make sure that these packages are installed by calling "univention-app install "%s=%s" --only-master-packages" on the host'
             % (host, app.id, app.version))
         return
     username = '******' % host
     try:
         if args.noninteractive:
             raise Abort()
         password = self._get_password_for(username)
         with self._get_password_file(password=password) as password_file:
             if not password_file:
                 raise Abort()
             # TODO: fallback if univention-app is not installed
             process = self._subprocess([
                 '/usr/sbin/univention-ssh', password_file, username,
                 'univention-app', 'install',
                 '%s=%s' % (app.id, app.version), '--only-master-packages',
                 '--noninteractive', '--do-not-send-info'
             ])
             if process.returncode != 0:
                 self.warn(
                     'Installing master packages for %s on %s failed!' %
                     (app.id, host))
     except Abort:
         if is_master:
             self.fatal('This is the DC master. Cannot continue!')
             raise
         else:
             self.warn(
                 'This is a DC backup. Continuing anyway, please rerun univention-app install %s --only-master-packages there later!'
                 % (app.id))
Ejemplo n.º 16
0
 def main(self, args):
     component_id = args.component_id
     app_id = None
     if args.new:
         component_id, app_id = self._create_new_repo(args)
     meta_inf_dir = os.path.join(args.path, 'meta-inf', args.ucs_version)
     if LooseVersion(args.ucs_version) >= '4.1':
         if app_id is None:
             if args.ini:
                 ini_file = args.ini
             else:
                 for root, dirnames, filenames in os.walk(meta_inf_dir):
                     for filename in filenames:
                         if filename == '%s.ini' % component_id:
                             ini_file = os.path.join(root, filename)
                             break
                     else:
                         continue
                     break
                 else:
                     raise Abort(
                         'Could not determine app id. Specify an --ini file!'
                     )
             app = App.from_ini(ini_file)
             app_id = app.id
         meta_inf_dir = os.path.join(meta_inf_dir, app_id)
     mkdir(meta_inf_dir)
     repo_dir = os.path.join(args.path, 'univention-repository',
                             args.ucs_version, 'maintained', 'component',
                             component_id)
     mkdir(repo_dir)
     if args.unmaintained:
         version = ucr_get('version/version')
         if args.ucs_version != version:
             self.fatal(
                 'Cannot easily set up unmaintained packages for %s (need %s). You need to download them into the repository manually. Sorry!'
                 % (args.ucs_version, version))
         else:
             self._copy_unmaintained_packages(repo_dir, args)
     app = self._copy_meta_files(component_id, meta_inf_dir, repo_dir, args)
     if app and args.packages:
         self._handle_packages(app, repo_dir, args)
         self._generate_repo_index_files(repo_dir)
     self._generate_meta_index_files(args)
     self.log('Component is: %s' % component_id)
Ejemplo n.º 17
0
 def _do_it(self, app, args):
     if self._install_only_master_packages(args):
         self._install_master_packages(app, unregister_if_uninstalled=True)
     else:
         self._register_files(app)
         self.percentage = 5
         self._register_app(app, args)
         self.percentage = 10
         self._register_database(app)
         self.percentage = 15
         self._register_attributes(app, args)
         self.percentage = 25
         if self._install_app(app, args):
             self.percentage = 80
             self._call_join_script(app, args)
             ucr_save({'appcenter/prudence/docker/%s' % app.id: 'yes'})
         else:
             raise Abort('Failed to install the App')
Ejemplo n.º 18
0
 def main(self, args):
     app = args.app
     if app._docker_prudence_is_true():
         apps = [
             _app for _app in Apps().get_all_apps_with_id(app.id)
             if not _app.docker
         ]
         if apps:
             app = sorted(apps)[-1]
             self.warn(
                 'Using %s instead of %s because docker is to be ignored' %
                 (app, args.app))
         else:
             raise Abort(
                 'Cannot use %s as docker is to be ignored, yet, only non-docker versions could be found'
                 % args.app)
     args.app = app
     return self.do_it(args)
Ejemplo n.º 19
0
    def _upgrade_image(self, app, args):
        docker = self._get_docker(app)

        self.log('Verifying Docker registry manifest for app image %s' %
                 docker.image)
        docker.verify()

        docker.pull()
        self.log('Saving data from old container (%s)' % self.old_app)
        old_docker = self._get_docker(self.old_app)
        old_container = old_docker.container
        if self._backup_container(self.old_app, backup_data='copy') is False:
            raise Abort('Could not backup container!')
        self._had_image_upgrade = True
        self.log('Setting up new container (%s)' % app)
        ucr_save({app.ucr_image_key: None})
        args.set_vars = self._get_config(self.old_app, args)
        self._install_new_app(app, args)
        self.log('Removing old container')
        if old_container:
            docker_rm(old_container)
        self._register_app(app, args)
        self._call_join_script(app, args)
        self.old_app = app
Ejemplo n.º 20
0
 def _show_license(self, app, args):
     if self._show_file(app, 'license_agreement', args,
                        agree=True) is False:
         raise Abort()
Ejemplo n.º 21
0
 def _copy_meta_files(self, component_id, meta_inf_dir, repo_dir, args):
     ini_file = os.path.join(meta_inf_dir, '%s.ini' % component_id)
     if args.clear:
         if os.path.exists(repo_dir):
             rmdir(repo_dir)
         if os.path.exists(ini_file):
             os.unlink(ini_file)
     if args.ini:
         self.copy_file(args.ini, ini_file)
     if not os.path.exists(ini_file):
         self.warn('Stopping here due to no ini file')
         return
     app_en = App.from_ini(ini_file, 'en')
     app_de = App.from_ini(ini_file, 'de')
     if args.clear:
         self._build_repo_dir(app_en, component_id, args.path,
                              args.ucs_version)
     if not app_en or not app_de:
         raise Abort('Cannot continue with flawed ini file')
     if args.logo:
         if LooseVersion(args.ucs_version) >= '4.1':
             parser = ConfigParser()
             parser.read(ini_file)
             try:
                 logo_fname = parser.get('Application', 'Logo')
             except NoOptionError:
                 self.fatal('No Logo specified in ini file!')
             else:
                 self.copy_file(args.logo,
                                os.path.join(meta_inf_dir, logo_fname))
         else:
             self.copy_file(
                 args.logo,
                 os.path.join(meta_inf_dir, '%s.png' % component_id))
     if args.logo_detail_page:
         parser = ConfigParser()
         parser.read(ini_file)
         try:
             logo_detail_fname = parser.get('Application', 'LogoDetailPage')
         except NoOptionError:
             self.fatal('No Logo specified in ini file!')
         self.copy_file(args.logo_detail_page,
                        os.path.join(meta_inf_dir, logo_detail_fname))
     if args.screenshot:
         self.copy_file(args.screenshot[0],
                        os.path.join(meta_inf_dir, app_en.screenshot))
         if len(args.screenshot) > 1:
             self.copy_file(args.screenshot[1],
                            os.path.join(meta_inf_dir, app_de.screenshot))
     if args.thumbnails:
         thumbnails = []
         for thumbnail in app_en.thumbnails + app_de.thumbnails:
             if thumbnail in thumbnails:
                 continue
             if thumbnail.startswith('http'):
                 continue
             thumbnails.append(thumbnail)
         for i, thumbnail in enumerate(args.thumbnails):
             try:
                 self.copy_file(thumbnail,
                                os.path.join(meta_inf_dir, thumbnails[i]))
             except IndexError:
                 raise Abort(
                     'The ini file must state as much Thumbnails= as --thumbnails are given'
                 )
     if args.readme:
         for readme in args.readme:
             self.copy_file(readme, repo_dir)
     if args.license:
         for license in args.license:
             self.copy_file(license, repo_dir)
     if args.ucr:
         self.copy_file(
             args.ucr,
             os.path.join(repo_dir, 'univention-config-registry-variables'))
     if args.schema:
         self.copy_file(args.schema, os.path.join(repo_dir, 'schema'))
     if args.attributes:
         self.copy_file(args.attributes,
                        os.path.join(repo_dir, 'attributes'))
     if args.preinst:
         self.copy_file(args.preinst, os.path.join(repo_dir, 'preinst'))
     if args.join:
         self.copy_file(args.join, os.path.join(repo_dir, 'inst'))
     if args.prerm:
         self.copy_file(args.prerm, os.path.join(repo_dir, 'prerm'))
     if args.unjoin:
         self.copy_file(args.unjoin, os.path.join(repo_dir, 'uinst'))
     if args.init:
         self.copy_file(args.init, os.path.join(repo_dir, 'init'))
     if args.setup:
         self.copy_file(args.setup, os.path.join(repo_dir, 'setup'))
     if args.store_data:
         self.copy_file(args.store_data,
                        os.path.join(repo_dir, 'store_data'))
     if args.restore_data_before_setup:
         self.copy_file(args.restore_data_before_setup,
                        os.path.join(repo_dir, 'restore_data_before_setup'))
     if args.restore_data_after_setup:
         self.copy_file(args.restore_data_after_setup,
                        os.path.join(repo_dir, 'restore_data_after_setup'))
     if args.update_available:
         self.copy_file(args.update_available,
                        os.path.join(repo_dir, 'update_available'))
     if args.update_packages:
         self.copy_file(args.update_packages,
                        os.path.join(repo_dir, 'update_packages'))
     if args.update_release:
         self.copy_file(args.update_release,
                        os.path.join(repo_dir, 'update_release'))
     if args.update_app_version:
         self.copy_file(args.update_app_version,
                        os.path.join(repo_dir, 'update_app_version'))
     if args.env:
         self.copy_file(args.env, os.path.join(repo_dir, 'env'))
     return app_en
Ejemplo n.º 22
0
 def _show_post_readme(self, app, args):
     if self._show_file(app, self.post_readme, args, confirm=True) is False:
         raise Abort()
Ejemplo n.º 23
0
 def _upgrade_packages(self, app, args):
     process = self._execute_container_script(app, 'update_packages', args)
     if not process or process.returncode != 0:
         raise Abort('Package upgrade script failed')
Ejemplo n.º 24
0
    def _start_docker_image(self, app, hostdn, password, args):
        docker = self._get_docker(app)
        if not docker:
            return

        self.log('Verifying Docker registry manifest for app image %s' %
                 docker.image)
        docker.verify()

        self.log('Downloading app image %s' % docker.image)
        docker.pull()

        self.log('Initializing app image')
        hostname = explode_dn(hostdn, 1)[0]
        set_vars = (args.set_vars or {}).copy()
        configure = get_action('configure')
        for variable in configure.list_config(app):
            if variable['value'] is not None and variable['id'] not in set_vars:
                set_vars[variable['id']] = variable['value']  # default
        set_vars['docker/host/name'] = '%s.%s' % (ucr_get('hostname'),
                                                  ucr_get('domainname'))
        set_vars['ldap/hostdn'] = hostdn
        set_vars['server/role'] = app.docker_server_role
        set_vars['update/warning/releasenotes'] = 'no'
        ucr_keys_list = list(ucr_keys())
        for var in [
                'nameserver.*', 'repository/online/server',
                'repository/app_center/server', 'update/secure_apt',
                'appcenter/index/verify', 'ldap/master.*', 'locale.*',
                'domainname'
        ]:
            for key in ucr_keys_list:
                if re.match(var, key):
                    set_vars[key] = ucr_get(key)
        if ucr_is_true('appcenter/docker/container/proxy/settings',
                       default=True):
            if ucr_get('proxy/http'):
                set_vars['proxy/http'] = ucr_get('proxy/http')
                set_vars['http_proxy'] = ucr_get('proxy/http')
            if ucr_get('proxy/https'):
                set_vars['proxy/https'] = ucr_get('proxy/https')
                set_vars['https_proxy'] = ucr_get('proxy/https')
            if ucr_get('proxy/no_proxy'):
                set_vars['proxy/no_proxy'] = ucr_get('proxy/no_proxy')
                set_vars['no_proxy'] = ucr_get('proxy/no_proxy')
        set_vars['updater/identify'] = 'Docker App'
        database_connector = DatabaseConnector.get_connector(app)
        database_password_file = None
        if database_connector:
            try:
                database_password = database_connector.get_db_password()
                database_password_file = database_connector.get_db_password_file(
                )
                if database_password:
                    set_vars[
                        app.
                        docker_env_database_host] = database_connector.get_db_host(
                        )
                    db_port = database_connector.get_db_port()
                    if db_port:
                        set_vars[app.docker_env_database_port] = db_port
                    set_vars[
                        app.
                        docker_env_database_name] = database_connector.get_db_name(
                        )
                    set_vars[
                        app.
                        docker_env_database_user] = database_connector.get_db_user(
                        )
                    if app.docker_env_database_password_file:
                        set_vars[
                            app.
                            docker_env_database_password_file] = database_password_file
                    else:
                        set_vars[
                            app.
                            docker_env_database_password] = database_password
                autostart_variable = database_connector.get_autostart_variable(
                )
                if autostart_variable:
                    set_vars[autostart_variable] = 'no'
            except DatabaseError as exc:
                raise Abort(str(exc))

        container = docker.create(hostname, set_vars)
        self.log('Preconfiguring container %s' % container)
        autostart = 'yes'
        if not Start.call(app=app):
            raise Abort('Unable to start the container!')
        time.sleep(3)
        if not docker.is_running():
            dlogs = docker.dockerd_logs()
            clogs = docker.logs()
            inspect = docker.inspect_container()
            msg = """
The container for {app} could not be started!

docker logs {container}:
{clogs}

dockerd logs:
{dlogs}

docker inspect:
{state}
{graphdriver}""".format(app=app,
                        container=docker.container,
                        clogs='\n'.join(clogs),
                        dlogs='\n'.join(dlogs),
                        state=inspect.get('State'),
                        graphdriver=inspect.get('GraphDriver'))
            raise AppCenterErrorContainerStart(msg)
        if password:
            with open(docker.path('/etc/machine.secret'), 'w+b') as f:
                f.write(password)
        self._copy_files_into_container(app, '/etc/timezone', '/etc/localtime',
                                        database_password_file)
        configure.call(app=app, autostart=autostart, set_vars=set_vars)