def test_404_connection(self): """Verify the apache status module gets disabled when hardening apache. Ported from amulet tests. """ logging.info('Checking apache mod_status gets disabled.') unit_name = zaza_model.get_lead_unit_name('openstack-dashboard') keystone_unit = zaza_model.get_lead_unit_name('keystone') dashboard_relation = openstack_juju.get_relation_from_unit( keystone_unit, unit_name, 'identity-service') dashboard_ip = dashboard_relation['private-address'] logging.debug("... dashboard_ip is:{}".format(dashboard_ip)) logging.debug('Maybe enabling hardening for apache...') _app_config = zaza_model.get_application_config(self.application_name) logging.info(_app_config['harden']) with self.config_change( {'harden': _app_config['harden'].get('value', '')}, {'harden': 'apache'}): try: urllib.request.urlopen( 'http://{}/server-status'.format(dashboard_ip)) except urllib.request.HTTPError as e: if e.code == 404: return # test failed if it didn't return 404 msg = "Apache mod_status check failed." assert False, msg
def get_application_ip(application, model_name=None): """Get the application's IP address. :param application: Application name :type application: str :param model_name: Name of model to query. :type model_name: str :returns: Application's IP address :rtype: str """ try: app_config = model.get_application_config( application, model_name=model_name) except KeyError: return '' vip = app_config.get("vip", {}).get("value") if vip: ip = vip else: unit = model.get_units( application, model_name=model_name)[0] ip = unit.public_address return ip
def test_404_connection(self): """Verify the apache status module gets disabled when hardening apache. Ported from amulet tests. """ logging.info('Checking apache mod_status gets disabled.') unit = zaza_model.get_unit_from_name( zaza_model.get_lead_unit_name(self.application_name)) logging.debug("... dashboard_ip is: {}".format(unit.public_address)) logging.debug('Maybe enabling hardening for apache...') _app_config = zaza_model.get_application_config(self.application_name) logging.info(_app_config['harden']) request = urllib.request.Request('http://{}/server-status'.format( unit.public_address)) with self.config_change( {'harden': _app_config['harden'].get('value', '')}, {'harden': 'apache'}): try: _do_request(request) except urllib.request.HTTPError as e: # test failed if it didn't return 404 msg = "Apache mod_status check failed." self.assertEqual(e.code, 404, msg) logging.info('OK')
def restart_on_changed_debug_oslo_config_file(self, config_file, services, config_section='DEFAULT'): """Check restart happens on config change by flipping debug mode. Change debug mode and assert that change propagates to the correct file and that services are restarted as a result. config_file must be an oslo config file and debug option must be set in the `config_section` section. :param config_file: OSLO Config file to check for settings :type config_file: str :param services: Services expected to be restarted when config_file is changed. :type services: list """ # Expected default and alternate values current_value = model.get_application_config( self.application_name)['debug']['value'] new_value = str(not bool(current_value)).title() current_value = str(current_value).title() set_default = {'debug': current_value} set_alternate = {'debug': new_value} default_entry = {config_section: {'debug': [current_value]}} alternate_entry = {config_section: {'debug': [new_value]}} # Make config change, check for service restarts logging.info('Changing settings on {} to {}'.format( self.application_name, set_alternate)) self.restart_on_changed(config_file, set_default, set_alternate, default_entry, alternate_entry, services)
def configure_cinder_backup(): """Configure cinder-backup-swift-proxy.""" keystone_ip = zaza_model.get_app_ips( 'swift-keystone')[0] swift_ip = zaza_model.get_app_ips( 'swift-proxy')[0] auth_ver = (zaza_model.get_application_config('swift-keystone') .get('preferred-api-version').get('value')) if auth_ver == 2: auth_url = 'http://{}:5000/v2.0'.format(keystone_ip) endpoint_url = 'http://{}:8080/v1/AUTH_'.format(swift_ip) else: auth_url = 'http://{}:5000/v3'.format(keystone_ip) endpoint_url = 'http://{}:8080/v1/AUTH'.format(swift_ip) cinder_backup_swift_proxy_conf = { 'endpoint-url': endpoint_url, 'auth-url': auth_url } juju_service = 'cinder-backup-swift-proxy' zaza_model.set_application_config(juju_service, cinder_backup_swift_proxy_conf) zaza_model.wait_for_agent_status() zaza_model.wait_for_application_states() _singleton = zaza.openstack.charm_tests.test_utils.OpenStackBaseTest() _singleton.setUpClass() with _singleton.config_change(cinder_backup_swift_proxy_conf, cinder_backup_swift_proxy_conf): # wait for configuration to be applied then return pass
def nfs_setup(): """Run setup for testing Trilio. Setup for testing Trilio is currently part of functional tests. """ logging.info("Configuring NFS Server") nfs_server_ip = zaza_model.get_app_ips("nfs-server-test-fixture")[0] trilio_wlm_unit = zaza_model.get_first_unit_name("trilio-wlm") nfs_shares_conf = {"nfs-shares": "{}:/srv/testing".format(nfs_server_ip)} logging.info("NFS share config: {}".format(nfs_shares_conf)) _trilio_services = ["trilio-wlm", "trilio-data-mover"] conf_changed = False for juju_service in _trilio_services: app_config = zaza_model.get_application_config(juju_service) if app_config["nfs-shares"] != nfs_shares_conf["nfs-shares"]: logging.info("Updating nfs-shares config option") zaza_model.set_application_config(juju_service, nfs_shares_conf) conf_changed = True if conf_changed: zaza_model.wait_for_agent_status() # NOTE(jamespage): wlm-api service must be running in order # to execute the setup actions zaza_model.block_until_service_status( unit_name=trilio_wlm_unit, services=["wlm-api"], target_status="active", )
def basic_overcloud_network(): """Run setup for neutron networking. Configure the following: The overcloud network using subnet pools """ cli_utils.setup_logging() # Get network configuration settings network_config = {} # Declared overcloud settings network_config.update(OVERCLOUD_NETWORK_CONFIG) # Default undercloud settings network_config.update(DEFAULT_UNDERCLOUD_NETWORK_CONFIG) # Environment specific settings network_config.update(generic_utils.get_undercloud_env_vars()) # Deployed model settings if (model.get_application_config('neutron-api').get('enable-dvr').get( 'value')): network_config.update({"dvr_enabled": True}) # Get keystone session keystone_session = openstack_utils.get_overcloud_keystone_session() # Handle network for Openstack-on-Openstack scenarios if juju_utils.get_provider_type() == "openstack": undercloud_ks_sess = openstack_utils.get_undercloud_keystone_session() network.setup_gateway_ext_port(network_config, keystone_session=undercloud_ks_sess) # Confugre the overcloud network network.setup_sdn(network_config, keystone_session=keystone_session)
def test_object_storage(self): """Verify object storage API. Verify that the object storage API works as expected. """ if self.multisite: raise unittest.SkipTest('Skipping REST API test, ' 'multisite configuration') logging.info('Checking Swift REST API') keystone_session = zaza_openstack.get_overcloud_keystone_session() region_name = zaza_model.get_application_config( self.application_name, model_name=self.model_name)['region']['value'] swift_client = zaza_openstack.get_swift_session_client( keystone_session, region_name, cacert=self.cacert, ) _container = 'demo-container' _test_data = 'Test data from Zaza' swift_client.put_container(_container) swift_client.put_object(_container, 'testfile', contents=_test_data, content_type='text/plain') _, content = swift_client.get_object(_container, 'testfile') self.assertEqual(content.decode('UTF-8'), _test_data)
def test_900_restart_on_config_change(self): """Verify that the specified services are restarted on config changed. Ported from amulet tests. """ logging.info("Testing restart on config changed.") # Expected default and alternate values current_value = zaza_model.get_application_config( self.application_name)['use-syslog']['value'] new_value = str(not bool(current_value)).title() current_value = str(current_value).title() # Expected default and alternate values set_default = {'use-syslog': current_value} set_alternate = {'use-syslog': new_value} # Services which are expected to restart upon config change, # and corresponding config files affected by the change services = ['apache2', 'memcached'] conf_file = '/etc/openstack-dashboard/local_settings.py' # Make config change, check for service restarts logging.info('Setting use-syslog on openstack-dashboard {}'.format( set_alternate)) self.restart_on_changed(conf_file, set_default, set_alternate, None, None, services)
def test_check_pool_types(self): """Check type of pools created for clients.""" app_pools = [('glance', 'glance'), ('nova-compute', 'nova'), ('cinder-ceph', 'cinder-ceph')] runtime_pool_details = zaza_ceph.get_ceph_pool_details() for app, pool_name in app_pools: juju_pool_config = zaza_model.get_application_config(app).get( 'pool-type') if juju_pool_config: expected_pool_type = juju_pool_config['value'] else: # If the pool-type option is absent assume the default of # replicated. expected_pool_type = zaza_ceph.REPLICATED_POOL_TYPE for pool_config in runtime_pool_details: if pool_config['pool_name'] == pool_name: logging.info('Checking {} is {}'.format( pool_name, expected_pool_type)) expected_pool_code = -1 if expected_pool_type == zaza_ceph.REPLICATED_POOL_TYPE: expected_pool_code = zaza_ceph.REPLICATED_POOL_CODE elif expected_pool_type == zaza_ceph.ERASURE_POOL_TYPE: expected_pool_code = zaza_ceph.ERASURE_POOL_CODE self.assertEqual(pool_config['type'], expected_pool_code) break else: raise CephPoolConfig( "Failed to find config for {}".format(pool_name))
def basic_setup(): """Run setup for testing Trilio. Setup for testing Trilio is currently part of functional tests. """ logging.info("Configuring NFS Server") nfs_server_ip = zaza_model.get_app_ips("nfs-server-test-fixture")[0] trilio_wlm_unit = zaza_model.get_first_unit_name("trilio-wlm") nfs_shares_conf = {"nfs-shares": "{}:/srv/testing".format(nfs_server_ip)} _trilio_services = ["trilio-wlm", "trilio-data-mover"] conf_changed = False for juju_service in _trilio_services: app_config = zaza_model.get_application_config(juju_service) if app_config["nfs-shares"] != nfs_shares_conf["nfs-shares"]: zaza_model.set_application_config(juju_service, nfs_shares_conf) conf_changed = True if conf_changed: zaza_model.wait_for_agent_status() # NOTE(jamespage): wlm-api service must be running in order # to execute the setup actions zaza_model.block_until_service_status( unit_name=trilio_wlm_unit, services=["wlm-api"], target_status="active", ) logging.info("Executing create-cloud-admin-trust") password = juju_utils.leader_get("keystone", "admin_passwd") generic_utils.assertActionRanOK( zaza_model.run_action_on_leader( "trilio-wlm", "create-cloud-admin-trust", raise_on_failure=True, action_params={"password": password}, ) ) logging.info("Executing create-license") test_license = os.environ.get("TEST_TRILIO_LICENSE") if test_license and os.path.exists(test_license): zaza_model.attach_resource("trilio-wlm", resource_name='license', resource_path=test_license) generic_utils.assertActionRanOK( zaza_model.run_action_on_leader( "trilio-wlm", "create-license", raise_on_failure=True ) ) else: logging.error("Unable to find Trilio License file")
def basic_setup(): """Run basic setup for Trilio apps.""" backup_target_type = zaza_model.get_application_config( 'trilio-wlm')['backup-target-type']['value'] if backup_target_type == "nfs": nfs_setup() if backup_target_type in ["s3", "experimental-s3"]: s3_setup() trust_setup() license_setup()
def get_new_config(self): """Return the config key and new value to trigger a hook execution. NOTE: The implementation assumes the charm has a `debug` option and If that is not true the derived class should override this method. :returns: Config key and new value :rtype: (str, bool) """ app_config = model.get_application_config(self.application_name) return 'debug', str(not app_config['debug']['value'])
def setUpClass(cls): """Run class setup for running glance tests with S3 backend.""" super(GlanceExternalS3Test, cls).setUpClass() cls.glance_client = openstack_utils.get_glance_session_client( cls.keystone_session) configs = model.get_application_config("glance") cls.s3_store_host = configs["s3-store-host"]["value"] cls.s3_store_access_key = configs["s3-store-access-key"]["value"] cls.s3_store_secret_key = configs["s3-store-secret-key"]["value"] cls.s3_store_bucket = configs["s3-store-bucket"]["value"]
def get_application_config_keys(application): """Return application configuration keys :param application: Name of application :type application: string :returns: List of aplication configuration keys :rtype: list """ application_config = model.get_application_config( lifecycle_utils.get_juju_model(), application) return list(application_config.keys())
def test_check_pool_types(self): """Check type of pools created for clients.""" app_pools = [ ('glance', 'glance'), ('nova-compute', 'nova'), ('cinder-ceph', 'cinder-ceph')] runtime_pool_details = zaza_ceph.get_ceph_pool_details() for app, pool_name in app_pools: try: app_config = zaza_model.get_application_config(app) except KeyError: logging.info( 'Skipping pool check of %s, application %s not present', pool_name, app) continue rel_id = zaza_model.get_relation_id( app, 'ceph-mon', remote_interface_name='client') if not rel_id: logging.info( 'Skipping pool check of %s, ceph relation not present', app) continue juju_pool_config = app_config.get('pool-type') if juju_pool_config: expected_pool_type = juju_pool_config['value'] else: # If the pool-type option is absent assume the default of # replicated. expected_pool_type = zaza_ceph.REPLICATED_POOL_TYPE for pool_config in runtime_pool_details: if pool_config['pool_name'] == pool_name: logging.info('Checking {} is {}'.format( pool_name, expected_pool_type)) expected_pool_code = -1 if expected_pool_type == zaza_ceph.REPLICATED_POOL_TYPE: expected_pool_code = zaza_ceph.REPLICATED_POOL_CODE elif expected_pool_type == zaza_ceph.ERASURE_POOL_TYPE: expected_pool_code = zaza_ceph.ERASURE_POOL_CODE self.assertEqual( pool_config['type'], expected_pool_code) break else: raise CephPoolConfig( "Failed to find config for {}".format(pool_name))
def get_application_config_option(application, option): """Return application configuration :param application: Name of application :type application: string :param option: Specific configuration option :type option: string :returns: Value of configuration option :rtype: Configuration option value type """ application_config = model.get_application_config( lifecycle_utils.get_juju_model(), application) try: return application_config.get(option).get('value') except AttributeError: return None
def encrypt_vip_endpoints(): """Apply certs and keys to all charms that support them.""" (cakey, cacert) = create_ca() ssl_vip_keys = ['vip', 'ssl_ca', 'ssl_cert', 'ssl_key'] status = model.get_status() for application_name in status.applications.keys(): app_config = model.get_application_config(application_name) if all(k in app_config for k in ssl_vip_keys): cn = app_config['vip'].get('value') # If there is no vip check if its a non-ha deploy. if not cn: units = model.get_units(application_name) if len(units) == 1: cn = units[0].public_address if cn: create_certs(application_name, cn, ISSUER_NAME, cakey) apply_certs(application_name) model.block_until_all_units_idle()
def get_application_ip(application): """Get the application's IP address. :param application: Application name :type application: str :returns: Application's IP address :rtype: str """ try: app_config = model.get_application_config(application) except KeyError: return '' vip = app_config.get("vip").get("value") if vip: ip = vip else: unit = model.get_units(application)[0] ip = unit.public_address return ip
def configure_cinder_backup(): """Configure cinder-backup-swift.""" keystone_ip = zaza_model.get_app_ips('swift-keystone')[0] swift_ip = zaza_model.get_app_ips('swift-proxy')[0] auth_ver = (zaza_model.get_application_config('swift-keystone').get( 'preferred-api-version').get('value')) if auth_ver == 2: auth_url = 'http://{}:5000/v2.0'.format(keystone_ip) endpoint_url = 'http://{}:8080/v1/AUTH_'.format(swift_ip) else: auth_url = 'http://{}:5000/v3'.format(keystone_ip) endpoint_url = 'http://{}:8080/v1/AUTH'.format(swift_ip) cinder_backup_swift_conf = { 'endpoint-url': endpoint_url, 'auth-url': auth_url } juju_service = 'cinder-backup-swift' zaza_model.set_application_config(juju_service, cinder_backup_swift_conf) zaza_model.wait_for_application_states() time.sleep(300)
def config_current(self, application_name=None, keys=None): """Get Current Config of an application normalized into key-values. :param application_name: String application name for use when called by a charm under test other than the object's application. :type application_name: Optional[str] :param keys: iterable of strs to index into the current config. If None, return all keys from the config :type keys: Optional[Iterable[str]] :return: Dictionary of requested config from application :rtype: Dict[str, Any] """ if not application_name: application_name = self.application_name _app_config = model.get_application_config(application_name) keys = keys or _app_config.keys() return {k: _app_config.get(k, {}).get('value') for k in keys}
def test_404_connection(self): """Verify the apache status module gets disabled when hardening apache. Ported from amulet tests. """ logging.info('Checking apache mod_status gets disabled.') unit_name = zaza_model.get_lead_unit_name('openstack-dashboard') keystone_unit = zaza_model.get_lead_unit_name('keystone') dashboard_relation = openstack_juju.get_relation_from_unit( keystone_unit, unit_name, 'identity-service') dashboard_ip = dashboard_relation['private-address'] logging.debug("... dashboard_ip is:{}".format(dashboard_ip)) logging.debug('Maybe enabling hardening for apache...') _app_config = zaza_model.get_application_config(self.application_name) logging.info(_app_config['harden']) # NOTE(ajkavanagh): it seems that apache2 doesn't start quickly enough # for the test, and so it gets reset errors; repeat until either that # stops or there is a failure @tenacity.retry(wait=tenacity.wait_exponential(multiplier=1, min=5, max=10), retry=tenacity.retry_if_exception_type( http.client.RemoteDisconnected), reraise=True) def _do_request(): return urllib.request.urlopen( 'http://{}/server-status'.format(dashboard_ip)) with self.config_change( {'harden': _app_config['harden'].get('value', '')}, {'harden': 'apache'}): try: _do_request() except urllib.request.HTTPError as e: # test failed if it didn't return 404 msg = "Apache mod_status check failed." self.assertEqual(e.code, 404, msg) logging.info('OK')
def test_404_connection(self): """Verify the apache status module gets disabled when hardening apache. Ported from amulet tests. """ logging.info('Checking apache mod_status gets disabled.') logging.debug('Maybe enabling hardening for apache...') _app_config = zaza_model.get_application_config(self.application_name) logging.info(_app_config['harden']) request = urllib.request.Request(self.get_horizon_url()) with self.config_change( {'harden': _app_config['harden'].get('value', '')}, {'harden': 'apache'}): try: _do_request(request, cafile=self.cacert) except urllib.request.HTTPError as e: # test failed if it didn't return 404 msg = "Apache mod_status check failed." self.assertEqual(e.code, 404, msg) logging.info('OK')
def get_base_url(self): """Return the base url for http(s) requests. :returns: URL :rtype: str """ vip = (zaza_model.get_application_config( self.application_name).get("vip").get("value")) if vip: ip = vip else: unit = zaza_model.get_unit_from_name( zaza_model.get_lead_unit_name(self.application_name)) ip = unit.public_address logging.debug("Dashboard ip is:{}".format(ip)) scheme = 'http' if self.use_https: scheme = 'https' url = '{}://{}'.format(scheme, ip) return url
def test_deferred_restarts(self): """Run deferred restart tests.""" app_config = model.get_application_config(self.application_name) auto_restart_config_key = 'enable-auto-restarts' if auto_restart_config_key not in app_config: raise unittest.SkipTest("Deferred restarts not implemented") # Ensure auto restarts are off. policy_file = '/etc/policy-rc.d/charm-{}.policy'.format( self.application_name) if app_config[auto_restart_config_key]['value']: logging.info("Turning off auto restarts") model.set_application_config( self.application_name, {auto_restart_config_key: 'False'}) logging.info("Waiting for {} to appear on units of {}".format( policy_file, self.application_name)) model.block_until_file_has_contents( self.application_name, policy_file, 'policy_requestor_name') # The block_until_file_has_contents ensures the change we waiting # for has happened, now just wait for any hooks to finish. logging.info("Waiting for units to be idle") model.block_until_all_units_idle() else: logging.info("Auto restarts already disabled") self.run_tests() # Finished so turn auto-restarts back on. logging.info("Turning on auto restarts") model.set_application_config( self.application_name, {auto_restart_config_key: 'True'}) model.block_until_file_missing( self.application_name, policy_file) model.block_until_all_units_idle() self.check_clear_hooks()
allocation_pools = subnet['allocation_pools'] self.cidr = subnet['cidr'] self.highest_assigned = netaddr.IPAddress(allocation_pools[0]['end']) # XXX look away now, nothing to see here, move along. # If there is less than 30 free ips in the network after the top # dhcp ip then eat into the top of the dhcp range available_ips = [] for element in list(netaddr.IPNetwork(self.cidr)): if element == netaddr.IPAddress(self.highest_assigned) or \ available_ips: available_ips.append(element) if len(available_ips) < 30: self.highest_assigned = self.highest_assigned - 30 def get_next(self): next_ip = self.highest_assigned + 1 if next_ip in list(netaddr.IPNetwork(self.cidr)): self.highest_assigned = self.highest_assigned + 1 return next_ip else: raise Exception("vip pool exhausted") cli_utils.setup_logging() vp = VipPool() juju_status = juju_utils.get_full_juju_status() for application in juju_status.applications.keys(): if 'vip' in model.get_application_config(application).keys(): model.set_application_config(application, {'vip': vp.get_next()}) mojo_utils.juju_wait_finished()
def juju_get_config_keys(application): service_config = model.get_application_config(application) return list(service_config.keys())
def config_change(self, default_config, alternate_config): """Run change config tests. Change config to `alternate_config`, wait for idle workload status, yield, return config to `default_config` and wait for idle workload status before return from function. Example usage: with self.config_change({'preferred-api-version': '2'}, {'preferred-api-version': '3'}): do_something() :param default_config: Dict of charm settings to set on completion :type default_config: dict :param alternate_config: Dict of charm settings to change to :type alternate_config: dict """ # we need to compare config values to what is already applied before # attempting to set them. otherwise the model will behave differently # than we would expect while waiting for completion of the change _app_config = model.get_application_config(self.application_name) app_config = {} # convert the more elaborate config structure from libjuju to something # we can compare to what the caller supplies to this function for k in alternate_config.keys(): # note that conversion to string for all values is due to # attempting to set any config with other types lead to Traceback app_config[k] = str(_app_config.get(k, {}).get('value', '')) if all(item in app_config.items() for item in alternate_config.items()): logging.debug('alternate_config equals what is already applied ' 'config') yield if default_config == alternate_config: logging.debug('default_config also equals what is already ' 'applied config') return logging.debug('alternate_config already set, and default_config ' 'needs to be applied before return') else: logging.debug( 'Changing charm setting to {}'.format(alternate_config)) model.set_application_config(self.application_name, alternate_config, model_name=self.model_name) logging.debug('Waiting for units to execute config-changed hook') model.wait_for_agent_status(model_name=self.model_name) logging.debug('Waiting for units to reach target states') model.wait_for_application_states(model_name=self.model_name, states=self.test_config.get( 'target_deploy_status', {})) # TODO: Optimize with a block on a specific application until idle. model.block_until_all_units_idle() yield logging.debug('Restoring charm setting to {}'.format(default_config)) model.set_application_config(self.application_name, default_config, model_name=self.model_name) logging.debug('Waiting for units to reach target states') model.wait_for_application_states(model_name=self.model_name, states=self.test_config.get( 'target_deploy_status', {})) # TODO: Optimize with a block on a specific application until idle. model.block_until_all_units_idle()
def juju_get(application, option): service_config = model.get_application_config(application) try: return service_config.get(option).get('value') except AttributeError: return None