class CheckOperations(object): def __init__(self, application, info): self.application = application self.info = info self.ucr = ConfigRegistry() self.ucr.load() @classmethod def installed(cls, application, info): print("Running checks if correctly installed..") checks = cls(application, info) return all( (checks._check_dpkg_installed_status(), checks._check_ucr_variables_exist(), checks._check_files_exist(), checks._check_ldap_object_exists(), checks._check_url_accessible())) @classmethod def uninstalled(cls, application, info): print("Running checks if correctly uninstalled..") checks = cls(application, info) return all((checks._check_dpkg_uninstalled_status(), checks._check_ucr_variables_dont_exist(), checks._check_ldap_object_doesnt_exist())) def _fail(self, message): msg = "Error in (un)installed checks for {}: {}" print(msg.format(self.application, message)) return False def _packages(self): for package in self.info.get("default_packages", list()): yield package master = ("domaincontroller_master", "domaincontroller_backup") if self.ucr.get("server/role") in master: for package in self.info.get("default_packages_master", list()): yield package def _dpkg_status(self, package): cmd = ["dpkg-query", "-f='${db:Status-Abbrev}xx'", "--show", package] output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) (expected_char, current_char) = output[:2] expected = { "u": "unknown", "i": "install", "h": "hold", "r": "remove", "p": "purge" }.get(expected_char, "unknown") current = { "n": "not-installed", "c": "config-files", "U": "unpacked", "H": "half-installed", "F": "half-configured", "W": "triggers-awaited", "t": "tritters-pending", "i": "installed" }.get(current_char, "unknown") return (expected, current) def _get_dn(self): app_version = self.info.get("version") ldap_base = self.ucr.get("ldap/base") dn = "univentionAppID={id}_{version},cn={id},cn=apps,cn=univention,{base}" return dn.format(id=self.application, version=app_version, base=ldap_base) def _check_url(self, protocol, port, interface): fqdn = '{}.{}'.format(self.ucr.get("hostname"), self.ucr.get("domainname")) url = "{}://{}:{}{}".format(protocol, fqdn, port, interface) response = requests.get(url, timeout=30, verify=False) try: response.raise_for_status() except requests.HTTPError: return self._fail("webinterface at {} not reachable".format(url)) refresh = lxml.html.fromstring( response.text).cssselect('meta[http-equiv="refresh"]') if refresh: link = refresh[0].attrib['content'].partition("=")[2] return self._check_url(protocol, port, link) return True def _check_dpkg_installed_status(self): for package in self._packages(): try: (expected, current) = self._dpkg_status(package) error = current != "installed" except subprocess.CalledProcessError: error = True if error: msg = "`dpkg -s {}` does not report as installed" return self._fail(msg.format(package)) print("OK - dpkg reports correctly installed") return True def _check_dpkg_uninstalled_status(self): for package in self._packages(): try: (expected, current) = self._dpkg_status(package) error = current not in ("not-installed", "unknown", "config-files") except subprocess.CalledProcessError as e: error = e.returncode != 1 if error: msg = "`dpkg -s {}` does not report as uninstalled" return self._fail(msg.format(package)) print("OK - dpkg reports correctly uninstalled") return True def _check_files_exist(self): for package in self._packages(): output = subprocess.check_output(["dpkg", "--listfiles", package]) for path in output.splitlines(): if not os.path.exists(path): msg = "{} from {} does not exist in filesystem" return self._fail(msg.format(path, package)) print("OK - All files exist in the filesystem after installation.") return True def _check_ucr_variables_exist(self): interface = self.info.get("web_interface") port_http = self.info.get("web_interface_port_http") port_https = self.info.get("web_interface_port_https") scheme = self.info.get("ucs_overview_category", "service") web_entries_base = "ucs/web/overview/entries/{}/{}".format( scheme, self.application) pairs = (("/link", interface), ("/port_http", str(port_http)), ("/port_https", str(port_https))) if interface and port_http and port_https: unequal = [ web_entries_base + ex for (ex, value) in pairs if self.ucr.get(web_entries_base + ex) != value ] if unequal: msg = "following UCR variables not set correctly: {}" return self._fail(msg.format(", ".join(unequal))) msg = "OK - All UCR variables ({}) set correctly after installation." print(msg.format(web_entries_base)) return True def _check_ucr_variables_dont_exist(self): repository = "repository/online/component/{}".format( self.info.get("component_id")) web_entries = "ucs/web/overview/entries/(admin|service)/{}".format( self.application) pattern = re.compile("{}|{}".format(repository, web_entries)) active = [key for key in self.ucr.keys() if pattern.match(key)] if active: msg = "following UCR variables still active: {}" return self._fail(msg.format(", ".join(active))) print("OK - All UCR variables removed after uninstallation.") return True def _check_ldap_object_exists(self): try: utils.verify_ldap_object(self._get_dn()) except utils.LDAPObjectNotFound as e: return self._fail("Not Found: " + str(e)) print("OK - LDAP object created after installation.") return True def _check_ldap_object_doesnt_exist(self): try: utils.verify_ldap_object(self._get_dn(), should_exist=False) except utils.LDAPUnexpectedObjectFound as e: return self._fail("Found unexpected: " + str(e)) print("OK - LDAP object removed after uninstallation.") return True def _check_url_accessible(self): interface = self.info.get("web_interface") port_http = self.info.get("web_interface_port_http") port_https = self.info.get("web_interface_port_https") if all((interface, port_http, port_https)) and \ self._check_url("http", port_http, interface) and \ self._check_url("https", port_https, interface): print("OK - Webinterface reachable after installation.") return True
'cn=dns,%(ldap/base)s' % configRegistry, 'cn=mail,%(ldap/base)s' % configRegistry, 'cn=samba,%(ldap/base)s' % configRegistry, 'cn=nagios,%(ldap/base)s' % configRegistry, 'cn=System,%(connector/ad/ldap/base)s' % configRegistry, 'ou=Grp Policy Users,%(connector/ad/ldap/base)s' % configRegistry, 'cn=Builtin,%(connector/ad/ldap/base)s' % configRegistry, 'cn=ForeignSecurityPrincipals,%(connector/ad/ldap/base)s' % configRegistry, 'ou=Domain Controllers,%(connector/ad/ldap/base)s' % configRegistry, 'cn=Program Data,%(connector/ad/ldap/base)s' % configRegistry, 'cn=Configuration,%(connector/ad/ldap/base)s' % configRegistry, 'cn=opsi,%(ldap/base)s' % configRegistry, 'cn=Microsoft Exchange System Objects,%(connector/ad/ldap/base)s' % configRegistry ] for k in configRegistry.keys(): if k.startswith('connector/ad/mapping/ignoresubtree/'): global_ignore_subtree.append(configRegistry.get(k)) user_ignore_list = ignore_filter_from_tmpl('(uid={0!e})(CN={0!e})', 'connector/ad/mapping/user/ignorelist') user_ignore_filter = configRegistry.get('connector/ad/mapping/user/ignorefilter', '') if user_ignore_filter and not user_ignore_filter.startswith('('): user_ignore_filter = '({})'.format(user_ignore_filter) user_ignore_filter = '(|{}{}{})'.format('(userAccountControl=2080)', user_ignore_filter, user_ignore_list) ignore_filter_parts = '(groupType=-2147483643)(groupType=4)(univentionGroupType=-2147483643)(univentionGroupType=4)' if configRegistry.is_false('connector/ad/mapping/group/grouptype', False): ignore_filter_parts += '(sambaGroupType=5)(groupType=5)' ignore_filter_parts += ignore_filter_from_attr('cn', 'connector/ad/mapping/group/ignorelist') group_ignore_filter = '(|{})'.format(ignore_filter_parts)