type: string
description: Keystone DB Password
default: admin
+ mysql_host:
+ type: string
+ description: MySQL Host (external database)
+ mysql_port:
+ type: int
+ description: MySQL Port (external database)
+ mysql_root_password:
+ type: string
+ description: MySQL Root Password (external database)
admin_username:
type: string
description: Admin username to be created when starting the service
site_url: Optional[str]
ingress_whitelist_source_range: Optional[str]
tls_secret_name: Optional[str]
+ mysql_host: Optional[str]
+ mysql_port: Optional[int]
+ mysql_root_password: Optional[str]
@validator("max_file_size")
def validate_max_file_size(cls, v):
ip_network(v)
return v
+ @validator("mysql_port")
+ def validate_mysql_port(cls, v):
+ if v and (v <= 0 or v >= 65535):
+ raise ValueError("Mysql port out of range")
+ return v
+
class ConfigLdapModel(ModelValidator):
ldap_enabled: bool
def _check_missing_dependencies(self, config: ConfigModel):
missing_relations = []
- if self.mysql_client.is_missing_data_in_unit():
+ if not config.mysql_host and self.mysql_client.is_missing_data_in_unit():
missing_relations.append("mysql")
if missing_relations:
raise RelationsMissing(missing_relations)
+ def _validate_mysql_config(self, config: ConfigModel):
+ invalid_values = []
+ if not config.mysql_root_password:
+ invalid_values.append("Mysql root password must be provided")
+
+ if invalid_values:
+ raise ValueError("Invalid values: " + ", ".join(invalid_values))
+
def _generate_keys(self) -> Tuple[List[str], List[str]]:
"""Generating new fernet tokens.
# Validate config
config = ConfigModel(**dict(self.config))
config_ldap = ConfigLdapModel(**dict(self.config))
+
+ if config.mysql_host and not self.mysql_client.is_missing_data_in_unit():
+ raise Exception("Mysql data cannot be provided via config and relation")
+
+ if config.mysql_host:
+ self._validate_mysql_config(config)
+
# Check relations
self._check_missing_dependencies(config)
+
# Create Builder for the PodSpec
pod_spec_builder = PodSpecV3Builder()
+
# Build Container
container_builder = ContainerV3Builder(self.app.name, image_info)
container_builder.add_port(name=self.app.name, port=PORT)
+
# Build files
credential_files, fernet_files = self._build_files(config)
container_builder.add_volume_config(
)
container_builder.add_envs(
{
- "DB_HOST": self.mysql_client.host,
- "DB_PORT": self.mysql_client.port,
+ "DB_HOST": config.mysql_host or self.mysql_client.host,
+ "DB_PORT": config.mysql_port or self.mysql_client.port,
"ROOT_DB_USER": "root",
- "ROOT_DB_PASSWORD": self.mysql_client.root_password,
+ "ROOT_DB_PASSWORD": config.mysql_root_password
+ or self.mysql_client.root_password,
"KEYSTONE_DB_PASSWORD": config.keystone_db_password,
"REGION_ID": config.region_id,
"KEYSTONE_HOST": self.app.name,
)
if config_ldap.ldap_enabled:
-
container_builder.add_envs(
{
"LDAP_AUTHENTICATION_DOMAIN_NAME": config_ldap.ldap_authentication_domain_name,
}
)
container = container_builder.build()
+
# Add container to pod spec
pod_spec_builder.add_container(container)
+
# Add ingress resources to pod spec if site url exists
if config.site_url:
parsed = urlparse(config.site_url)
self.config = {
"region_id": "str",
"keystone_db_password": "str",
+ "mysql_host": "",
+ "mysql_port": 3306,
+ "mysql_root_password": "manopw",
"admin_username": "str",
"admin_password": "str",
"admin_project": "str",
# Assertions
self.assertIsInstance(self.harness.charm.unit.status, ActiveStatus)
+ def test_with_config(self) -> NoReturn:
+ "Test with mysql config"
+ self.initialize_mysql_config()
+ # Verifying status
+ self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
+
def test_with_relations(
self,
) -> NoReturn:
# Verifying status
self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
+ def test_exception_mysql_relation_and_config(
+ self,
+ ) -> NoReturn:
+ "Test with relations and config. Must throw exception"
+ self.initialize_mysql_config()
+ self.initialize_mysql_relation()
+ # Verifying status
+ self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
+
+ def initialize_mysql_config(self):
+ self.harness.update_config(
+ {
+ "mysql_host": "mysql",
+ "mysql_port": 3306,
+ "mysql_root_password": "manopw",
+ }
+ )
+
def initialize_mysql_relation(self):
relation_id = self.harness.add_relation("db", "mysql")
self.harness.add_relation_unit(relation_id, "mysql/0")
ignore =
W291,
W293,
+ W503,
E123,
E125,
E226,
description: Database common key
type: string
default: osm
+ mongodb_uri:
+ type: string
+ description: MongoDB URI (external database)
log_level:
description: "Log Level"
type: string
vca_cloud: str
vca_k8s_cloud: str
database_commonkey: str
+ mongodb_uri: Optional[str]
log_level: str
vca_apiproxy: Optional[str]
# Model-config options
raise ValueError("value must be INFO or DEBUG")
return v
+ @validator("mongodb_uri")
+ def validate_mongodb_uri(cls, v):
+ if v and not v.startswith("mongodb://"):
+ raise ValueError("mongodb_uri is not properly formed")
+ return v
+
class LcmCharm(CharmedOsmBase):
def __init__(self, *args) -> NoReturn:
if self.kafka_client.is_missing_data_in_unit():
missing_relations.append("kafka")
- if self.mongodb_client.is_missing_data_in_unit():
+ if not config.mongodb_uri and self.mongodb_client.is_missing_data_in_unit():
missing_relations.append("mongodb")
if self.ro_client.is_missing_data_in_app():
missing_relations.append("ro")
def build_pod_spec(self, image_info):
# Validate config
config = ConfigModel(**dict(self.config))
+
+ if config.mongodb_uri and not self.mongodb_client.is_missing_data_in_unit():
+ raise Exception("Mongodb data cannot be provided via config and relation")
+
# Check relations
self._check_missing_dependencies(config)
+
# Create Builder for the PodSpec
pod_spec_builder = PodSpecV3Builder()
+
# Build Container
container_builder = ContainerV3Builder(self.app.name, image_info)
container_builder.add_port(name=self.app.name, port=PORT)
"OSMLCM_MESSAGE_PORT": self.kafka_client.port,
# Database configuration
"OSMLCM_DATABASE_DRIVER": "mongo",
- "OSMLCM_DATABASE_URI": self.mongodb_client.connection_string,
+ "OSMLCM_DATABASE_URI": config.mongodb_uri
+ or self.mongodb_client.connection_string,
"OSMLCM_DATABASE_COMMONKEY": config.database_commonkey,
# Storage configuration
"OSMLCM_STORAGE_DRIVER": "mongo",
for k, v in self.config.items()
if k.startswith("vca_model_config")
}
+
if model_config_envs:
container_builder.add_envs(model_config_envs)
+
container = container_builder.build()
+
# Add container to pod spec
pod_spec_builder.add_container(container)
+
return pod_spec_builder.build()
"vca_cloud": "cloud",
"vca_k8s_cloud": "k8scloud",
"database_commonkey": "commonkey",
+ "mongodb_uri": "",
"log_level": "INFO",
}
self.harness.update_config(self.config)
# Assertions
self.assertIsInstance(self.harness.charm.unit.status, ActiveStatus)
+ def test_with_relations_and_mongodb_config(
+ self,
+ ) -> NoReturn:
+ "Test with relations and mongodb config"
+ self.initialize_kafka_relation()
+ self.initialize_mongo_config()
+ self.initialize_ro_relation()
+ # Verifying status
+ self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
+
def test_with_relations(
self,
) -> NoReturn:
# Verifying status
self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
+ def test_exception_mongodb_relation_and_config(
+ self,
+ ) -> NoReturn:
+ "Test with all relations and config for mongodb. Must fail"
+ self.initialize_mongo_relation()
+ self.initialize_mongo_config()
+ # Verifying status
+ self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
+
def test_build_pod_spec(
self,
) -> NoReturn:
kafka_relation_id, "kafka/0", {"host": "kafka", "port": 9092}
)
+ def initialize_mongo_config(self):
+ self.harness.update_config({"mongodb_uri": "mongodb://mongo:27017"})
+
def initialize_mongo_relation(self):
mongodb_relation_id = self.harness.add_relation("mongodb", "mongodb")
self.harness.add_relation_unit(mongodb_relation_id, "mongodb/0")
ignore =
W291,
W293,
+ W503,
E123,
E125,
E226,
description: Database common key
type: string
default: osm
+ mongodb_uri:
+ type: string
+ description: MongoDB URI (external database)
collector_interval:
description: Collector interval
type: int
vca_secret: str
vca_cacert: str
database_commonkey: str
+ mongodb_uri: Optional[str]
log_level: str
openstack_default_granularity: int
global_request_timeout: int
_extract_certificates(v)
return v
+ @validator("mongodb_uri")
+ def validate_mongodb_uri(cls, v):
+ if v and not v.startswith("mongodb://"):
+ raise ValueError("mongodb_uri is not properly formed")
+ return v
+
@property
def certificates_dict(cls):
return _extract_certificates(cls.certificates) if cls.certificates else {}
if self.kafka_client.is_missing_data_in_unit():
missing_relations.append("kafka")
- if self.mongodb_client.is_missing_data_in_unit():
+ if not config.mongodb_uri and self.mongodb_client.is_missing_data_in_unit():
missing_relations.append("mongodb")
if self.prometheus_client.is_missing_data_in_app():
missing_relations.append("prometheus")
def build_pod_spec(self, image_info):
# Validate config
config = ConfigModel(**dict(self.config))
+
+ if config.mongodb_uri and not self.mongodb_client.is_missing_data_in_unit():
+ raise Exception("Mongodb data cannot be provided via config and relation")
+
# Check relations
self._check_missing_dependencies(config)
+
# Create Builder for the PodSpec
pod_spec_builder = PodSpecV3Builder()
+
# Build Container
container_builder = ContainerV3Builder(self.app.name, image_info)
certs_files = self._build_cert_files(config)
+
if certs_files:
container_builder.add_volume_config("certs", "/certs", certs_files)
+
container_builder.add_port(name=self.app.name, port=PORT)
container_builder.add_envs(
{
"OSMMON_MESSAGE_PORT": self.kafka_client.port,
# Database configuration
"OSMMON_DATABASE_DRIVER": "mongo",
- "OSMMON_DATABASE_URI": self.mongodb_client.connection_string,
+ "OSMMON_DATABASE_URI": config.mongodb_uri
+ or self.mongodb_client.connection_string,
"OSMMON_DATABASE_COMMONKEY": config.database_commonkey,
# Prometheus configuration
"OSMMON_PROMETHEUS_URL": f"http://{self.prometheus_client.hostname}:{self.prometheus_client.port}",
"OSMMON_KEYSTONE_SERVICE_PROJECT": self.keystone_client.service,
}
)
-
container = container_builder.build()
+
# Add container to pod spec
pod_spec_builder.add_container(container)
+
return pod_spec_builder.build()
"vca_secret": "admin",
"vca_cacert": "cacert",
"database_commonkey": "commonkey",
+ "mongodb_uri": "",
"log_level": "INFO",
"openstack_default_granularity": 10,
"global_request_timeout": 10,
# Assertions
self.assertIsInstance(self.harness.charm.unit.status, ActiveStatus)
+ def test_with_relations_and_mongodb_config(
+ self,
+ ) -> NoReturn:
+ "Test with relations (internal)"
+ self.initialize_kafka_relation()
+ self.initialize_mongo_config()
+ self.initialize_prometheus_relation()
+ self.initialize_keystone_relation()
+ # Verifying status
+ self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
+
def test_with_relations(
self,
) -> NoReturn:
# Verifying status
self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
+ def test_exception_mongodb_relation_and_config(
+ self,
+ ) -> NoReturn:
+ "Test with relations and config for mongodb. Must fail"
+ self.initialize_mongo_relation()
+ self.initialize_mongo_config()
+ # Verifying status
+ self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
+
def initialize_kafka_relation(self):
kafka_relation_id = self.harness.add_relation("kafka", "kafka")
self.harness.add_relation_unit(kafka_relation_id, "kafka/0")
kafka_relation_id, "kafka/0", {"host": "kafka", "port": 9092}
)
+ def initialize_mongo_config(self):
+ self.harness.update_config({"mongodb_uri": "mongodb://mongo:27017"})
+
def initialize_mongo_relation(self):
mongodb_relation_id = self.harness.add_relation("mongodb", "mongodb")
self.harness.add_relation_unit(mongodb_relation_id, "mongodb/0")
ignore =
W291,
W293,
+ W503,
E123,
E125,
E226,
type: boolean
description: Enable test endpoints of NBI.
default: false
+ mongodb_uri:
+ type: string
+ description: MongoDB URI (external database)
cluster_issuer: Optional[str]
ingress_whitelist_source_range: Optional[str]
tls_secret_name: Optional[str]
+ mongodb_uri: Optional[str]
@validator("auth_backend")
def validate_auth_backend(cls, v):
ip_network(v)
return v
+ @validator("mongodb_uri")
+ def validate_mongodb_uri(cls, v):
+ if v and not v.startswith("mongodb://"):
+ raise ValueError("mongodb_uri is not properly formed")
+ return v
+
class NbiCharm(CharmedOsmBase):
def __init__(self, *args) -> NoReturn:
if self.kafka_client.is_missing_data_in_unit():
missing_relations.append("kafka")
- if self.mongodb_client.is_missing_data_in_unit():
+ if not config.mongodb_uri and self.mongodb_client.is_missing_data_in_unit():
missing_relations.append("mongodb")
if self.prometheus_client.is_missing_data_in_app():
missing_relations.append("prometheus")
def build_pod_spec(self, image_info):
# Validate config
config = ConfigModel(**dict(self.config))
+
+ if config.mongodb_uri and not self.mongodb_client.is_missing_data_in_unit():
+ raise Exception("Mongodb data cannot be provided via config and relation")
+
# Check relations
self._check_missing_dependencies(config)
+
# Create Builder for the PodSpec
pod_spec_builder = PodSpecV3Builder()
+
# Build Init Container
pod_spec_builder.add_init_container(
{
],
}
)
+
# Build Container
container_builder = ContainerV3Builder(self.app.name, image_info)
container_builder.add_port(name=self.app.name, port=PORT)
"OSMNBI_MESSAGE_PORT": self.kafka_client.port,
# Database configuration
"OSMNBI_DATABASE_DRIVER": "mongo",
- "OSMNBI_DATABASE_URI": self.mongodb_client.connection_string,
+ "OSMNBI_DATABASE_URI": config.mongodb_uri
+ or self.mongodb_client.connection_string,
"OSMNBI_DATABASE_COMMONKEY": config.database_commonkey,
# Storage configuration
"OSMNBI_STORAGE_DRIVER": "mongo",
}
)
container = container_builder.build()
+
# Add container to pod spec
pod_spec_builder.add_container(container)
+
# Add ingress resources to pod spec if site url exists
if config.site_url:
parsed = urlparse(config.site_url)
ingress_resource_builder.add_rule(parsed.hostname, self.app.name, PORT)
ingress_resource = ingress_resource_builder.build()
pod_spec_builder.add_ingress_resource(ingress_resource)
+
logger.debug(pod_spec_builder.build())
+
return pod_spec_builder.build()
"enable_test": False,
"auth_backend": "internal",
"database_commonkey": "key",
+ "mongodb_uri": "",
"log_level": "INFO",
"max_file_size": 0,
"ingress_whitelist_source_range": "",
# Assertions
self.assertIsInstance(self.harness.charm.unit.status, ActiveStatus)
+ def test_with_relations_internal_and_mongodb_config(
+ self,
+ ) -> NoReturn:
+ "Test with relations and mongodb config (internal)"
+ self.initialize_kafka_relation()
+ self.initialize_mongo_config()
+ self.initialize_prometheus_relation()
+ # Verifying status
+ self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
+
def test_with_relations_internal(
self,
) -> NoReturn:
# Verifying status
self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
+ def test_with_relations_and_mongodb_config_with_keystone_missing(
+ self,
+ ) -> NoReturn:
+ "Test with relations and mongodb config (keystone)"
+ self.harness.update_config({"auth_backend": "keystone"})
+ self.initialize_kafka_relation()
+ self.initialize_mongo_config()
+ self.initialize_prometheus_relation()
+ # Verifying status
+ self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
+ self.assertTrue("keystone" in self.harness.charm.unit.status.message)
+
def test_with_relations_keystone_missing(
self,
) -> NoReturn:
self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
self.assertTrue("keystone" in self.harness.charm.unit.status.message)
+ def test_with_relations_and_mongodb_config_with_keystone(
+ self,
+ ) -> NoReturn:
+ "Test with relations (keystone)"
+ self.harness.update_config({"auth_backend": "keystone"})
+ self.initialize_kafka_relation()
+ self.initialize_mongo_config()
+ self.initialize_prometheus_relation()
+ self.initialize_keystone_relation()
+ # Verifying status
+ self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
+
def test_with_relations_keystone(
self,
) -> NoReturn:
# Verifying status
self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
+ def test_mongodb_exception_relation_and_config(
+ self,
+ ) -> NoReturn:
+ self.initialize_mongo_config()
+ self.initialize_mongo_relation()
+ # Verifying status
+ self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
+
def initialize_kafka_relation(self):
kafka_relation_id = self.harness.add_relation("kafka", "kafka")
self.harness.add_relation_unit(kafka_relation_id, "kafka/0")
kafka_relation_id, "kafka/0", {"host": "kafka", "port": 9092}
)
+ def initialize_mongo_config(self):
+ self.harness.update_config({"mongodb_uri": "mongodb://mongo:27017"})
+
def initialize_mongo_relation(self):
mongodb_relation_id = self.harness.add_relation("mongodb", "mongodb")
self.harness.add_relation_unit(mongodb_relation_id, "mongodb/0")
ignore =
W291,
W293,
+ W503,
E123,
E125,
E226,
description: Common Key for Mongo database
type: string
default: osm
+ mongodb_uri:
+ type: string
+ description: MongoDB URI (external database)
import logging
-from typing import NoReturn
+from typing import NoReturn, Optional
from ops.main import main
from opslib.osm.charm import CharmedOsmBase, RelationsMissing
class ConfigModel(ModelValidator):
database_commonkey: str
+ mongodb_uri: Optional[str]
log_level: str
@validator("log_level")
raise ValueError("value must be INFO or DEBUG")
return v
+ @validator("mongodb_uri")
+ def validate_mongodb_uri(cls, v):
+ if v and not v.startswith("mongodb://"):
+ raise ValueError("mongodb_uri is not properly formed")
+ return v
+
class PlaCharm(CharmedOsmBase):
def __init__(self, *args) -> NoReturn:
if self.kafka_client.is_missing_data_in_unit():
missing_relations.append("kafka")
- if self.mongodb_client.is_missing_data_in_unit():
+ if not config.mongodb_uri and self.mongodb_client.is_missing_data_in_unit():
missing_relations.append("mongodb")
if missing_relations:
def build_pod_spec(self, image_info):
# Validate config
config = ConfigModel(**dict(self.config))
+
+ if config.mongodb_uri and not self.mongodb_client.is_missing_data_in_unit():
+ raise Exception("Mongodb data cannot be provided via config and relation")
+
# Check relations
self._check_missing_dependencies(config)
+
# Create Builder for the PodSpec
pod_spec_builder = PodSpecV3Builder()
+
# Build Container
container_builder = ContainerV3Builder(self.app.name, image_info)
container_builder.add_port(name=self.app.name, port=PORT)
"OSMPLA_MESSAGE_PORT": self.kafka_client.port,
# Database configuration
"OSMPLA_DATABASE_DRIVER": "mongo",
- "OSMPLA_DATABASE_URI": self.mongodb_client.connection_string,
+ "OSMPLA_DATABASE_URI": config.mongodb_uri
+ or self.mongodb_client.connection_string,
"OSMPLA_DATABASE_COMMONKEY": config.database_commonkey,
}
)
container = container_builder.build()
+
# Add container to pod spec
pod_spec_builder.add_container(container)
+
return pod_spec_builder.build()
self.harness.begin()
self.config = {
"log_level": "INFO",
+ "mongodb_uri": "",
}
self.harness.update_config(self.config)
# Assertions
self.assertIsInstance(self.harness.charm.unit.status, ActiveStatus)
+ def test_with_relations_and_mongodb_config(
+ self,
+ ) -> NoReturn:
+ "Test with relations and mongodb config (internal)"
+ self.initialize_kafka_relation()
+ self.initialize_mongo_config()
+ # Verifying status
+ self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
+
def test_with_relations(
self,
) -> NoReturn:
# Verifying status
self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
+ def test_exception_mongodb_relation_and_config(
+ self,
+ ) -> NoReturn:
+ "Test with relation and config for Mongodb. Test must fail"
+ self.initialize_mongo_relation()
+ self.initialize_mongo_config()
+ # Verifying status
+ self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
+
def initialize_kafka_relation(self):
kafka_relation_id = self.harness.add_relation("kafka", "kafka")
self.harness.add_relation_unit(kafka_relation_id, "kafka/0")
kafka_relation_id, "kafka/0", {"host": "kafka", "port": 9092}
)
+ def initialize_mongo_config(self):
+ self.harness.update_config({"mongodb_uri": "mongodb://mongo:27017"})
+
def initialize_mongo_relation(self):
mongodb_relation_id = self.harness.add_relation("mongodb", "mongodb")
self.harness.add_relation_unit(mongodb_relation_id, "mongodb/0")
ignore =
W291,
W293,
+ W503,
E123,
E125,
E226,
description: "Log Level"
type: string
default: "INFO"
+ mongodb_uri:
+ type: string
+ description: MongoDB URI (external database)
import logging
-from typing import NoReturn
+from typing import NoReturn, Optional
from ops.main import main
from opslib.osm.charm import CharmedOsmBase, RelationsMissing
class ConfigModel(ModelValidator):
log_level: str
+ mongodb_uri: Optional[str]
@validator("log_level")
def validate_log_level(cls, v):
raise ValueError("value must be INFO or DEBUG")
return v
+ @validator("mongoddb_uri")
+ def validate_mongodb_uri(cls, v):
+ if v and not v.startswith("mongodb://"):
+ raise ValueError("mongodb_uri is not properly formed")
+ return v
+
class PolCharm(CharmedOsmBase):
def __init__(self, *args) -> NoReturn:
if self.kafka_client.is_missing_data_in_unit():
missing_relations.append("kafka")
- if self.mongodb_client.is_missing_data_in_unit():
+ if not config.mongodb_uri and self.mongodb_client.is_missing_data_in_unit():
missing_relations.append("mongodb")
if missing_relations:
def build_pod_spec(self, image_info):
# Validate config
config = ConfigModel(**dict(self.config))
+
+ if config.mongodb_uri and not self.mongodb_client.is_missing_data_in_unit():
+ raise Exception("Mongodb data cannot be provided via config and relation")
+
# Check relations
self._check_missing_dependencies(config)
+
# Create Builder for the PodSpec
pod_spec_builder = PodSpecV3Builder()
+
# Build Container
container_builder = ContainerV3Builder(self.app.name, image_info)
container_builder.add_port(name=self.app.name, port=PORT)
"OSMPOL_MESSAGE_PORT": self.kafka_client.port,
# Database configuration
"OSMPOL_DATABASE_DRIVER": "mongo",
- "OSMPOL_DATABASE_URI": self.mongodb_client.connection_string,
+ "OSMPOL_DATABASE_URI": config.mongodb_uri
+ or self.mongodb_client.connection_string,
}
)
-
container = container_builder.build()
+
# Add container to pod spec
pod_spec_builder.add_container(container)
+
return pod_spec_builder.build()
self.harness.begin()
self.config = {
"log_level": "INFO",
+ "mongodb_uri": "",
}
self.harness.update_config(self.config)
# Assertions
self.assertIsInstance(self.harness.charm.unit.status, ActiveStatus)
+ def test_with_relations_and_mongodb_config(
+ self,
+ ) -> NoReturn:
+ "Test with relations and mongodb config (internal)"
+ self.initialize_kafka_relation()
+ self.initialize_mongo_config()
+ # Verifying status
+ self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
+
def test_with_relations(
self,
) -> NoReturn:
# Verifying status
self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
+ def test_exception_mongodb_relation_and_config(
+ self,
+ ) -> NoReturn:
+ "Test with relation and config for Mongodb. Must fail"
+ self.initialize_mongo_relation()
+ self.initialize_mongo_config()
+ # Verifying status
+ self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
+
def initialize_kafka_relation(self):
kafka_relation_id = self.harness.add_relation("kafka", "kafka")
self.harness.add_relation_unit(kafka_relation_id, "kafka/0")
kafka_relation_id, "kafka/0", {"host": "kafka", "port": 9092}
)
+ def initialize_mongo_config(self):
+ self.harness.update_config({"mongodb_uri": "mongodb://mongo:27017"})
+
def initialize_mongo_relation(self):
mongodb_relation_id = self.harness.add_relation("mongodb", "mongodb")
self.harness.add_relation_unit(mongodb_relation_id, "mongodb/0")
ignore =
W291,
W293,
+ W503,
E123,
E125,
E226,
description: Database COMMON KEY
type: string
default: osm
+ mongodb_uri:
+ type: string
+ description: MongoDB URI (external database)
log_level:
description: "Log Level"
type: string
default: "INFO"
+ mysql_host:
+ type: string
+ description: MySQL Host (external database)
+ mysql_port:
+ type: int
+ description: MySQL Port (external database)
+ mysql_user:
+ type: string
+ description: MySQL User (external database)
+ mysql_password:
+ type: string
+ description: MySQL Password (external database)
+ mysql_root_password:
+ type: string
+ description: MySQL Root Password (external database)
vim_database:
type: string
description: "The database name."
class ConfigModel(ModelValidator):
enable_ng_ro: bool
database_commonkey: str
+ mongodb_uri: Optional[str]
log_level: str
+ mysql_host: Optional[str]
+ mysql_port: Optional[int]
+ mysql_user: Optional[str]
+ mysql_password: Optional[str]
+ mysql_root_password: Optional[str]
vim_database: str
ro_database: str
openmano_tenant: str
_extract_certificates(v)
return v
+ @validator("mongodb_uri")
+ def validate_mongodb_uri(cls, v):
+ if v and not v.startswith("mongodb://"):
+ raise ValueError("mongodb_uri is not properly formed")
+ return v
+
+ @validator("mysql_port")
+ def validate_mysql_port(cls, v):
+ if v and (v <= 0 or v >= 65535):
+ raise ValueError("Mysql port out of range")
+ return v
+
@property
def certificates_dict(cls):
return _extract_certificates(cls.certificates) if cls.certificates else {}
if config.enable_ng_ro:
if self.kafka_client.is_missing_data_in_unit():
missing_relations.append("kafka")
- if self.mongodb_client.is_missing_data_in_unit():
+ if not config.mongodb_uri and self.mongodb_client.is_missing_data_in_unit():
missing_relations.append("mongodb")
else:
- if self.mysql_client.is_missing_data_in_unit():
+ if not config.mysql_host and self.mysql_client.is_missing_data_in_unit():
missing_relations.append("mysql")
if missing_relations:
raise RelationsMissing(missing_relations)
+ def _validate_mysql_config(self, config: ConfigModel):
+ invalid_values = []
+ if not config.mysql_user:
+ invalid_values.append("Mysql user is empty")
+ if not config.mysql_password:
+ invalid_values.append("Mysql password is empty")
+ if not config.mysql_root_password:
+ invalid_values.append("Mysql root password empty")
+
+ if invalid_values:
+ raise ValueError("Invalid values: " + ", ".join(invalid_values))
+
def _build_cert_files(
self,
config: ConfigModel,
def build_pod_spec(self, image_info):
# Validate config
config = ConfigModel(**dict(self.config))
+
+ if config.enable_ng_ro:
+ if config.mongodb_uri and not self.mongodb_client.is_missing_data_in_unit():
+ raise Exception(
+ "Mongodb data cannot be provided via config and relation"
+ )
+ else:
+ if config.mysql_host and not self.mysql_client.is_missing_data_in_unit():
+ raise Exception("Mysql data cannot be provided via config and relation")
+
+ if config.mysql_host:
+ self._validate_mysql_config(config)
+
# Check relations
self._check_missing_dependencies(config)
+
# Create Builder for the PodSpec
pod_spec_builder = PodSpecV3Builder()
+
# Build Container
container_builder = ContainerV3Builder(self.app.name, image_info)
certs_files = self._build_cert_files(config)
+
if certs_files:
container_builder.add_volume_config("certs", "/certs", certs_files)
+
container_builder.add_port(name=self.app.name, port=PORT)
container_builder.add_http_readiness_probe(
"/ro/" if config.enable_ng_ro else "/openmano/tenants",
"OSMRO_LOG_LEVEL": config.log_level,
}
)
+
if config.enable_ng_ro:
container_builder.add_envs(
{
"OSMRO_MESSAGE_PORT": self.kafka_client.port,
# MongoDB configuration
"OSMRO_DATABASE_DRIVER": "mongo",
- "OSMRO_DATABASE_URI": self.mongodb_client.connection_string,
+ "OSMRO_DATABASE_URI": config.mongodb_uri
+ or self.mongodb_client.connection_string,
"OSMRO_DATABASE_COMMONKEY": config.database_commonkey,
}
)
else:
container_builder.add_envs(
{
- "RO_DB_HOST": self.mysql_client.host,
- "RO_DB_OVIM_HOST": self.mysql_client.host,
- "RO_DB_PORT": self.mysql_client.port,
- "RO_DB_OVIM_PORT": self.mysql_client.port,
- "RO_DB_USER": self.mysql_client.user,
- "RO_DB_OVIM_USER": self.mysql_client.user,
- "RO_DB_PASSWORD": self.mysql_client.password,
- "RO_DB_OVIM_PASSWORD": self.mysql_client.password,
- "RO_DB_ROOT_PASSWORD": self.mysql_client.root_password,
- "RO_DB_OVIM_ROOT_PASSWORD": self.mysql_client.root_password,
+ "RO_DB_HOST": config.mysql_host or self.mysql_client.host,
+ "RO_DB_OVIM_HOST": config.mysql_host or self.mysql_client.host,
+ "RO_DB_PORT": config.mysql_port or self.mysql_client.port,
+ "RO_DB_OVIM_PORT": config.mysql_port or self.mysql_client.port,
+ "RO_DB_USER": config.mysql_user or self.mysql_client.user,
+ "RO_DB_OVIM_USER": config.mysql_user or self.mysql_client.user,
+ "RO_DB_PASSWORD": config.mysql_password
+ or self.mysql_client.password,
+ "RO_DB_OVIM_PASSWORD": config.mysql_password
+ or self.mysql_client.password,
+ "RO_DB_ROOT_PASSWORD": config.mysql_root_password
+ or self.mysql_client.root_password,
+ "RO_DB_OVIM_ROOT_PASSWORD": config.mysql_root_password
+ or self.mysql_client.root_password,
"RO_DB_NAME": config.ro_database,
"RO_DB_OVIM_NAME": config.vim_database,
"OPENMANO_TENANT": config.openmano_tenant,
}
)
container = container_builder.build()
+
# Add container to pod spec
pod_spec_builder.add_container(container)
+
return pod_spec_builder.build()
self.config = {
"enable_ng_ro": True,
"database_commonkey": "commonkey",
+ "mongodb_uri": "",
"log_level": "INFO",
"vim_database": "db_name",
"ro_database": "ro_db_name",
# Assertions
self.assertIsInstance(self.harness.charm.unit.status, ActiveStatus)
+ def test_with_relations_and_mongodb_config_ng(
+ self,
+ ) -> NoReturn:
+ "Test with relations (ng-ro)"
+
+ # Initializing the kafka relation
+ kafka_relation_id = self.harness.add_relation("kafka", "kafka")
+ self.harness.add_relation_unit(kafka_relation_id, "kafka/0")
+ self.harness.update_relation_data(
+ kafka_relation_id, "kafka/0", {"host": "kafka", "port": 9092}
+ )
+
+ # Initializing the mongodb config
+ self.harness.update_config({"mongodb_uri": "mongodb://mongo:27017"})
+
+ # Verifying status
+ self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
+
def test_with_relations_ng(
self,
) -> NoReturn:
# Verifying status
self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
+ def test_ng_exception_mongodb_relation_and_config(
+ self,
+ ) -> NoReturn:
+ "Test NG-RO mongodb relation and config. Must fail"
+ # Initializing the mongo relation
+ mongodb_relation_id = self.harness.add_relation("mongodb", "mongodb")
+ self.harness.add_relation_unit(mongodb_relation_id, "mongodb/0")
+ self.harness.update_relation_data(
+ mongodb_relation_id,
+ "mongodb/0",
+ {"connection_string": "mongodb://mongo:27017"},
+ )
+
+ # Initializing the mongodb config
+ self.harness.update_config({"mongodb_uri": "mongodb://mongo:27017"})
+
+ # Verifying status
+ self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
+
if __name__ == "__main__":
unittest.main()
ignore =
W291,
W293,
+ W503,
E123,
E125,
E226,