Adding manual external DB URI config
Change-Id: I24782d5b9594aebae2ec97b1196acfa2bafb6dbd
Signed-off-by: sousaedu <eduardo.sousa@canonical.com>
diff --git a/installers/charm/keystone/config.yaml b/installers/charm/keystone/config.yaml
index 2758d1c..402096c 100644
--- a/installers/charm/keystone/config.yaml
+++ b/installers/charm/keystone/config.yaml
@@ -45,6 +45,15 @@
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
diff --git a/installers/charm/keystone/src/charm.py b/installers/charm/keystone/src/charm.py
index 5d8d317..b5ce0cc 100755
--- a/installers/charm/keystone/src/charm.py
+++ b/installers/charm/keystone/src/charm.py
@@ -80,6 +80,9 @@
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):
@@ -101,6 +104,12 @@
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
@@ -170,11 +179,19 @@
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.
@@ -229,13 +246,23 @@
# 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(
@@ -246,10 +273,11 @@
)
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,
@@ -263,7 +291,6 @@
)
if config_ldap.ldap_enabled:
-
container_builder.add_envs(
{
"LDAP_AUTHENTICATION_DOMAIN_NAME": config_ldap.ldap_authentication_domain_name,
@@ -325,8 +352,10 @@
}
)
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)
diff --git a/installers/charm/keystone/tests/test_charm.py b/installers/charm/keystone/tests/test_charm.py
index d16e75d..e281b20 100644
--- a/installers/charm/keystone/tests/test_charm.py
+++ b/installers/charm/keystone/tests/test_charm.py
@@ -42,6 +42,9 @@
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",
@@ -83,6 +86,12 @@
# 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:
@@ -91,6 +100,24 @@
# 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")
diff --git a/installers/charm/keystone/tox.ini b/installers/charm/keystone/tox.ini
index d0d2570..cb37bc8 100644
--- a/installers/charm/keystone/tox.ini
+++ b/installers/charm/keystone/tox.ini
@@ -108,6 +108,7 @@
ignore =
W291,
W293,
+ W503,
E123,
E125,
E226,
diff --git a/installers/charm/lcm/config.yaml b/installers/charm/lcm/config.yaml
index 6301622..0f0cebb 100644
--- a/installers/charm/lcm/config.yaml
+++ b/installers/charm/lcm/config.yaml
@@ -59,6 +59,9 @@
description: Database common key
type: string
default: osm
+ mongodb_uri:
+ type: string
+ description: MongoDB URI (external database)
log_level:
description: "Log Level"
type: string
diff --git a/installers/charm/lcm/src/charm.py b/installers/charm/lcm/src/charm.py
index e9552fd..52bc5cf 100755
--- a/installers/charm/lcm/src/charm.py
+++ b/installers/charm/lcm/src/charm.py
@@ -51,6 +51,7 @@
vca_cloud: str
vca_k8s_cloud: str
database_commonkey: str
+ mongodb_uri: Optional[str]
log_level: str
vca_apiproxy: Optional[str]
# Model-config options
@@ -114,6 +115,12 @@
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:
@@ -136,7 +143,7 @@
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")
@@ -147,10 +154,16 @@
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)
@@ -169,7 +182,8 @@
"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",
@@ -195,11 +209,15 @@
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()
diff --git a/installers/charm/lcm/tests/test_charm.py b/installers/charm/lcm/tests/test_charm.py
index 831e176..3e6b2a4 100644
--- a/installers/charm/lcm/tests/test_charm.py
+++ b/installers/charm/lcm/tests/test_charm.py
@@ -49,6 +49,7 @@
"vca_cloud": "cloud",
"vca_k8s_cloud": "k8scloud",
"database_commonkey": "commonkey",
+ "mongodb_uri": "",
"log_level": "INFO",
}
self.harness.update_config(self.config)
@@ -79,6 +80,16 @@
# 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:
@@ -89,6 +100,15 @@
# 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:
@@ -200,6 +220,9 @@
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")
diff --git a/installers/charm/lcm/tox.ini b/installers/charm/lcm/tox.ini
index 30e0ea8..f207ac3 100644
--- a/installers/charm/lcm/tox.ini
+++ b/installers/charm/lcm/tox.ini
@@ -108,6 +108,7 @@
ignore =
W291,
W293,
+ W503,
E123,
E125,
E226,
diff --git a/installers/charm/mon/config.yaml b/installers/charm/mon/config.yaml
index f6d1ae1..d06b68d 100644
--- a/installers/charm/mon/config.yaml
+++ b/installers/charm/mon/config.yaml
@@ -36,6 +36,9 @@
description: Database common key
type: string
default: osm
+ mongodb_uri:
+ type: string
+ description: MongoDB URI (external database)
collector_interval:
description: Collector interval
type: int
diff --git a/installers/charm/mon/src/charm.py b/installers/charm/mon/src/charm.py
index ab6dd2d..8c0a6bc 100755
--- a/installers/charm/mon/src/charm.py
+++ b/installers/charm/mon/src/charm.py
@@ -70,6 +70,7 @@
vca_secret: str
vca_cacert: str
database_commonkey: str
+ mongodb_uri: Optional[str]
log_level: str
openstack_default_granularity: int
global_request_timeout: int
@@ -92,6 +93,12 @@
_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 {}
@@ -126,7 +133,7 @@
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")
@@ -149,15 +156,23 @@
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(
{
@@ -174,7 +189,8 @@
"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}",
@@ -200,10 +216,11 @@
"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()
diff --git a/installers/charm/mon/tests/test_charm.py b/installers/charm/mon/tests/test_charm.py
index dcf74ed..a7cef20 100644
--- a/installers/charm/mon/tests/test_charm.py
+++ b/installers/charm/mon/tests/test_charm.py
@@ -76,6 +76,7 @@
"vca_secret": "admin",
"vca_cacert": "cacert",
"database_commonkey": "commonkey",
+ "mongodb_uri": "",
"log_level": "INFO",
"openstack_default_granularity": 10,
"global_request_timeout": 10,
@@ -112,6 +113,17 @@
# 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:
@@ -123,6 +135,15 @@
# 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")
@@ -130,6 +151,9 @@
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")
diff --git a/installers/charm/mon/tox.ini b/installers/charm/mon/tox.ini
index 30e0ea8..f207ac3 100644
--- a/installers/charm/mon/tox.ini
+++ b/installers/charm/mon/tox.ini
@@ -108,6 +108,7 @@
ignore =
W291,
W293,
+ W503,
E123,
E125,
E226,
diff --git a/installers/charm/nbi/config.yaml b/installers/charm/nbi/config.yaml
index ef0792b..a3d94bc 100644
--- a/installers/charm/nbi/config.yaml
+++ b/installers/charm/nbi/config.yaml
@@ -64,3 +64,6 @@
type: boolean
description: Enable test endpoints of NBI.
default: false
+ mongodb_uri:
+ type: string
+ description: MongoDB URI (external database)
diff --git a/installers/charm/nbi/src/charm.py b/installers/charm/nbi/src/charm.py
index 1f5812a..550c88b 100755
--- a/installers/charm/nbi/src/charm.py
+++ b/installers/charm/nbi/src/charm.py
@@ -59,6 +59,7 @@
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):
@@ -92,6 +93,12 @@
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:
@@ -134,7 +141,7 @@
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")
@@ -148,10 +155,16 @@
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(
{
@@ -164,6 +177,7 @@
],
}
)
+
# Build Container
container_builder = ContainerV3Builder(self.app.name, image_info)
container_builder.add_port(name=self.app.name, port=PORT)
@@ -189,7 +203,8 @@
"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",
@@ -219,8 +234,10 @@
}
)
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)
@@ -254,7 +271,9 @@
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()
diff --git a/installers/charm/nbi/tests/test_charm.py b/installers/charm/nbi/tests/test_charm.py
index 6543335..116c06b 100644
--- a/installers/charm/nbi/tests/test_charm.py
+++ b/installers/charm/nbi/tests/test_charm.py
@@ -43,6 +43,7 @@
"enable_test": False,
"auth_backend": "internal",
"database_commonkey": "key",
+ "mongodb_uri": "",
"log_level": "INFO",
"max_file_size": 0,
"ingress_whitelist_source_range": "",
@@ -78,6 +79,16 @@
# 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:
@@ -88,6 +99,18 @@
# 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:
@@ -100,6 +123,18 @@
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:
@@ -112,6 +147,14 @@
# 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")
@@ -119,6 +162,9 @@
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")
diff --git a/installers/charm/nbi/tox.ini b/installers/charm/nbi/tox.ini
index 30e0ea8..f207ac3 100644
--- a/installers/charm/nbi/tox.ini
+++ b/installers/charm/nbi/tox.ini
@@ -108,6 +108,7 @@
ignore =
W291,
W293,
+ W503,
E123,
E125,
E226,
diff --git a/installers/charm/pla/config.yaml b/installers/charm/pla/config.yaml
index ae90304..1820188 100644
--- a/installers/charm/pla/config.yaml
+++ b/installers/charm/pla/config.yaml
@@ -24,3 +24,6 @@
description: Common Key for Mongo database
type: string
default: osm
+ mongodb_uri:
+ type: string
+ description: MongoDB URI (external database)
diff --git a/installers/charm/pla/src/charm.py b/installers/charm/pla/src/charm.py
index 15ae095..d9dfaa4 100755
--- a/installers/charm/pla/src/charm.py
+++ b/installers/charm/pla/src/charm.py
@@ -24,7 +24,7 @@
import logging
-from typing import NoReturn
+from typing import NoReturn, Optional
from ops.main import main
from opslib.osm.charm import CharmedOsmBase, RelationsMissing
@@ -44,6 +44,7 @@
class ConfigModel(ModelValidator):
database_commonkey: str
+ mongodb_uri: Optional[str]
log_level: str
@validator("log_level")
@@ -52,6 +53,12 @@
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:
@@ -70,7 +77,7 @@
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:
@@ -79,10 +86,16 @@
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)
@@ -97,14 +110,17 @@
"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()
diff --git a/installers/charm/pla/tests/test_charm.py b/installers/charm/pla/tests/test_charm.py
index 80cb315..debc378 100644
--- a/installers/charm/pla/tests/test_charm.py
+++ b/installers/charm/pla/tests/test_charm.py
@@ -41,6 +41,7 @@
self.harness.begin()
self.config = {
"log_level": "INFO",
+ "mongodb_uri": "",
}
self.harness.update_config(self.config)
@@ -70,6 +71,15 @@
# 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:
@@ -79,6 +89,15 @@
# 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")
@@ -86,6 +105,9 @@
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")
diff --git a/installers/charm/pla/tox.ini b/installers/charm/pla/tox.ini
index 30e0ea8..f207ac3 100644
--- a/installers/charm/pla/tox.ini
+++ b/installers/charm/pla/tox.ini
@@ -108,6 +108,7 @@
ignore =
W291,
W293,
+ W503,
E123,
E125,
E226,
diff --git a/installers/charm/pol/config.yaml b/installers/charm/pol/config.yaml
index 1ae26a4..59f695b 100644
--- a/installers/charm/pol/config.yaml
+++ b/installers/charm/pol/config.yaml
@@ -24,3 +24,6 @@
description: "Log Level"
type: string
default: "INFO"
+ mongodb_uri:
+ type: string
+ description: MongoDB URI (external database)
diff --git a/installers/charm/pol/src/charm.py b/installers/charm/pol/src/charm.py
index d339e1c..b2e5883 100755
--- a/installers/charm/pol/src/charm.py
+++ b/installers/charm/pol/src/charm.py
@@ -24,7 +24,7 @@
import logging
-from typing import NoReturn
+from typing import NoReturn, Optional
from ops.main import main
from opslib.osm.charm import CharmedOsmBase, RelationsMissing
@@ -44,6 +44,7 @@
class ConfigModel(ModelValidator):
log_level: str
+ mongodb_uri: Optional[str]
@validator("log_level")
def validate_log_level(cls, v):
@@ -51,6 +52,12 @@
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:
@@ -69,7 +76,7 @@
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:
@@ -78,10 +85,16 @@
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)
@@ -96,13 +109,15 @@
"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()
diff --git a/installers/charm/pol/tests/test_charm.py b/installers/charm/pol/tests/test_charm.py
index 32b1acd..089b6e5 100644
--- a/installers/charm/pol/tests/test_charm.py
+++ b/installers/charm/pol/tests/test_charm.py
@@ -40,6 +40,7 @@
self.harness.begin()
self.config = {
"log_level": "INFO",
+ "mongodb_uri": "",
}
self.harness.update_config(self.config)
@@ -69,6 +70,15 @@
# 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:
@@ -78,6 +88,15 @@
# 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")
@@ -85,6 +104,9 @@
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")
diff --git a/installers/charm/pol/tox.ini b/installers/charm/pol/tox.ini
index 30e0ea8..f207ac3 100644
--- a/installers/charm/pol/tox.ini
+++ b/installers/charm/pol/tox.ini
@@ -108,6 +108,7 @@
ignore =
W291,
W293,
+ W503,
E123,
E125,
E226,
diff --git a/installers/charm/ro/config.yaml b/installers/charm/ro/config.yaml
index bb667d7..0d3c9a0 100644
--- a/installers/charm/ro/config.yaml
+++ b/installers/charm/ro/config.yaml
@@ -28,10 +28,28 @@
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."
diff --git a/installers/charm/ro/src/charm.py b/installers/charm/ro/src/charm.py
index 5b40c16..951f281 100755
--- a/installers/charm/ro/src/charm.py
+++ b/installers/charm/ro/src/charm.py
@@ -62,7 +62,13 @@
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
@@ -80,6 +86,18 @@
_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 {}
@@ -126,14 +144,26 @@
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,
@@ -146,15 +176,32 @@
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",
@@ -177,6 +224,7 @@
"OSMRO_LOG_LEVEL": config.log_level,
}
)
+
if config.enable_ng_ro:
container_builder.add_envs(
{
@@ -185,7 +233,8 @@
"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,
}
)
@@ -193,24 +242,30 @@
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()
diff --git a/installers/charm/ro/tests/test_charm.py b/installers/charm/ro/tests/test_charm.py
index 9cced45..2d317bd 100644
--- a/installers/charm/ro/tests/test_charm.py
+++ b/installers/charm/ro/tests/test_charm.py
@@ -71,6 +71,7 @@
self.config = {
"enable_ng_ro": True,
"database_commonkey": "commonkey",
+ "mongodb_uri": "",
"log_level": "INFO",
"vim_database": "db_name",
"ro_database": "ro_db_name",
@@ -115,6 +116,24 @@
# 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:
@@ -139,6 +158,25 @@
# 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()
diff --git a/installers/charm/ro/tox.ini b/installers/charm/ro/tox.ini
index 30e0ea8..f207ac3 100644
--- a/installers/charm/ro/tox.ini
+++ b/installers/charm/ro/tox.ini
@@ -108,6 +108,7 @@
ignore =
W291,
W293,
+ W503,
E123,
E125,
E226,