Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -645,119 +645,119 @@
"hashed_secret": "a12337323b638ab044b1166bff4b1a1f83162819",
"is_secret": false,
"is_verified": false,
"line_number": 829,
"line_number": 832,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "fb947972c92f052c0a08866d182be0075a2b601b",
"is_secret": false,
"is_verified": false,
"line_number": 838,
"line_number": 841,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "03e227627ab8681281fdb8aa3d799b03f782d672",
"is_secret": false,
"is_verified": false,
"line_number": 2030,
"line_number": 2034,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "ef5f3d909f23bd0aa02b4253f98350384f709c86",
"is_secret": false,
"is_verified": false,
"line_number": 2137,
"line_number": 2141,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "cb1ae2b504c4615841d8144267a131231d2bd677",
"is_secret": false,
"is_verified": false,
"line_number": 2138,
"line_number": 2142,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "1a1e70e87dd0452c42f33ce9bf74aa28134dba6b",
"is_secret": false,
"is_verified": false,
"line_number": 2139,
"line_number": 2143,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "7b1ba2f04f2f1604dc4e3caffcadf9fcbce7df5b",
"is_secret": false,
"is_verified": false,
"line_number": 2140,
"line_number": 2144,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "0fa3b21ced80146d752888f2b60ec80e0d4b8925",
"is_secret": false,
"is_verified": false,
"line_number": 2145,
"line_number": 2149,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "f084f2068494b8d1cd06811dd97d02c3d85f40ee",
"is_secret": false,
"is_verified": false,
"line_number": 2160,
"line_number": 2164,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "adfa401a3b0a733d8f00519ac8c6b3893a2e7e8e",
"is_secret": false,
"is_verified": false,
"line_number": 2161,
"line_number": 2165,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "898e46bbadc12f87120548bd445eb4210c8407c8",
"is_secret": false,
"is_verified": false,
"line_number": 2169,
"line_number": 2173,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "f57ccec6b8f7b12b635ab53d26c3bf7300247341",
"is_secret": false,
"is_verified": false,
"line_number": 2170,
"line_number": 2174,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "77b044ea736f8cbe568d1954424186d901f89db9",
"is_secret": false,
"is_verified": false,
"line_number": 2171,
"line_number": 2175,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "d64368f12ca17c69568c6a132f17d44d56e60660",
"is_secret": false,
"is_verified": false,
"line_number": 2172,
"line_number": 2176,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "8f9ca35156c02cb6ba58c5b51230b9bedc38de4f",
"is_secret": false,
"is_verified": false,
"line_number": 2173,
"line_number": 2177,
"type": "Secret Keyword",
"verified_result": null
},
Expand Down
183 changes: 145 additions & 38 deletions ocs_ci/deployment/helpers/external_cluster_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,11 @@ def __init__(self, host, user, password=None, ssh_key=None):
"No SSH Auth to connect to external RHCS cluster provided! "
"Either password or SSH key is missing in EXTERNAL_MODE['login'] section!"
)
# adding jump host configuration to connect to external RHCS cluster on ibmcloud via jump host
self.jump_host = None
if config.ENV_DATA.get("platform") == constants.IBMCLOUD_PLATFORM:
self.jump_host = config.DEPLOYMENT.get("ssh_jump_host", None)
if self.jump_host and not self.jump_host.get("private_key"):
self.jump_host["private_key"] = os.path.expanduser(
config.DEPLOYMENT["ssh_key_private"]
)
self.jump_host = config.DEPLOYMENT.get("ssh_jump_host")
if self.jump_host and not self.jump_host.get("private_key"):
ssh_key_private = config.DEPLOYMENT.get("ssh_key_private")
if ssh_key_private:
self.jump_host["private_key"] = os.path.expanduser(ssh_key_private)

self.rhcs_conn = Connection(
host=self.host,
Expand Down Expand Up @@ -169,30 +166,33 @@ def exec_external_ceph_cmd(
raise exception_class(f"{error_msg}: {err}")
return retcode, out, err

def get_external_cluster_details(self):
def build_exporter_base_params(self, include_rgw=True):
"""
Gets the external RHCS cluster details and updates to config.EXTERNAL_MODE
Build the base parameter string for the exporter script.

Raises:
ExternalClusterExporterRunFailed: If exporter script failed to run on external RHCS cluster

"""
# get rgw endpoint port
rgw_endpoint_port = self.get_rgw_endpoint_api_port()
Reads cluster config to construct the flags needed by
create-external-cluster-resources.py. This method has no side effects
(does not modify config, delete users, or create namespaces).

# get rgw endpoint
rgw_endpoint = get_rgw_endpoint()
rgw_endpoint_with_port = f"{rgw_endpoint}:{rgw_endpoint_port}"
Args:
include_rgw (bool): If True (default), include --rgw-endpoint.
Set to False for clusters without RGW deployed.

# get ceph filesystem
ceph_fs_name = config.ENV_DATA.get("cephfs_name") or self.get_ceph_fs()
Returns:
str: Parameter string for run_exporter_script().

"""
rbd_name = config.ENV_DATA.get("rbd_name") or defaults.RBD_NAME
cluster_name = config.ENV_DATA.get("cluster_name") or defaults.RHCS_CLUSTER_NAME

params = (
f"--rbd-data-pool-name {rbd_name} --rgw-endpoint {rgw_endpoint_with_port}"
)
params = f"--rbd-data-pool-name {rbd_name}"

if include_rgw:
rgw_endpoint_port = self.get_rgw_endpoint_api_port()
rgw_endpoint = get_rgw_endpoint()
params += f" --rgw-endpoint {rgw_endpoint}:{rgw_endpoint_port}"

ceph_fs_name = config.ENV_DATA.get("cephfs_name") or self.get_ceph_fs()

if config.ENV_DATA["restricted-auth-permission"]:
if config.ENV_DATA["use_k8s_cluster_name"]:
Expand All @@ -207,8 +207,6 @@ def get_external_cluster_details(self):
f"{params} --restricted-auth-permission true --cluster-name {cluster_name} "
f"--alias-rbd-data-pool-name {alias_rbd_name}"
)
config.ENV_DATA["restricted-auth-permission"] = True
config.ENV_DATA["alias_rbd_name"] = alias_rbd_name

if config.ENV_DATA.get("rgw-realm"):
rgw_realm = config.ENV_DATA["rgw-realm"]
Expand All @@ -219,6 +217,41 @@ def get_external_cluster_details(self):
f"--rgw-zone-name {rgw_zone}"
)

if config.EXTERNAL_MODE.get("run_as_user"):
ceph_user = config.EXTERNAL_MODE["run_as_user"]
params = f"{params} --run-as-user {ceph_user}"

if config.EXTERNAL_MODE.get("use_rbd_namespace"):
rbd_namespace = config.EXTERNAL_MODE.get("rbd_namespace")
if rbd_namespace:
params = f"{params} --rados-namespace {rbd_namespace}"
if "restricted-auth-permission" not in params:
params += " --restricted-auth-permission true"
if "cluster-name" not in params:
params += f" --k8s-cluster-name {cluster_name}"

return params

def get_external_cluster_details(self):
"""
Gets the external RHCS cluster details and updates to config.EXTERNAL_MODE

Raises:
ExternalClusterExporterRunFailed: If exporter script failed to run on external RHCS cluster

"""
rbd_name = config.ENV_DATA.get("rbd_name") or defaults.RBD_NAME
cluster_name = config.ENV_DATA.get("cluster_name") or defaults.RHCS_CLUSTER_NAME

params = self.build_exporter_base_params()

# Side effects that must only run during deployment/upgrade
if "." in rbd_name or "_" in rbd_name:
config.ENV_DATA["restricted-auth-permission"] = True
config.ENV_DATA["alias_rbd_name"] = rbd_name.replace(".", "-").replace(
"_", "-"
)
Comment thread
coderabbitai[bot] marked this conversation as resolved.

# remove user 'rgw-admin-ops-user' if it exists since user creation is handled by
# external python script with necessary caps
if config.MULTICLUSTER.get(
Expand All @@ -230,22 +263,21 @@ def get_external_cluster_details(self):
else:
self.remove_rgw_user()

if config.EXTERNAL_MODE.get("run_as_user"):
ceph_user = config.EXTERNAL_MODE["run_as_user"]
params = f"{params} --run-as-user {ceph_user}"

if config.EXTERNAL_MODE.get("use_rbd_namespace"):
rbd_namespace = config.EXTERNAL_MODE.get("rbd_namespace")
if not rbd_namespace:
rbd_namespace = self.create_rbd_namespace(rbd=rbd_name)
config.EXTERNAL_MODE["rbd_namespace"] = rbd_namespace

params = f"{params} --rados-namespace {rbd_namespace}"
if "restricted-auth-permission" not in params:
params += " --restricted-auth-permission true"
# Append params that build_exporter_base_params skipped
# (namespace didn't exist in config yet when it ran)
params += f" --rados-namespace {rbd_namespace}"
if "restricted-auth-permission" not in params:
params += " --restricted-auth-permission true"
if "cluster-name" not in params:
params += f" --k8s-cluster-name {cluster_name}"

if not config.ENV_DATA.get("restricted-auth-permission"):
config.ENV_DATA["restricted-auth-permission"] = True
if "cluster-name" not in params:
params += f" --k8s-cluster-name {cluster_name}"

out = self.run_exporter_script(params=params)

Expand All @@ -269,16 +301,17 @@ def upload_exporter_script(self):
if ocs_version <= version.VERSION_4_18:
use_configmap = False
script_path = generate_exporter_script(use_configmap=use_configmap)
remote_script_path = f"/tmp/{os.path.basename(script_path)}"
upload_file(
self.host,
script_path,
script_path,
remote_script_path,
self.user,
self.password,
self.ssh_key,
ssh_connection=self.rhcs_conn if self.jump_host else None,
)
return script_path
return remote_script_path

def upload_rgw_cert_ca(self):
"""
Expand Down Expand Up @@ -1021,6 +1054,80 @@ def cleanup_zone_crush_rules(self, rule_names: list[str]) -> None:

logger.info("Cleanup of CRUSH rules completed")

def create_topology_pools(
self,
pool_names: list[str],
pool_size: int = 3,
pg_num: int = 32,
) -> list[str]:
"""
Create replicated RBD pools for topology-aware provisioning.

Unlike create_replica_one_pools(), this creates standard replicated pools
(size >= 2) without per-zone CRUSH rules — the default replicated_rule
distributes replicas across hosts automatically.

For each pool executes:
- ceph osd pool create <pool-name> <pg_num> <pg_num> replicated
- ceph osd pool set <pool-name> size <pool_size>
- ceph osd pool application enable <pool-name> rbd

Args:
pool_names (list[str]): List of pool names to create.
pool_size (int): Replication factor (default 3).
pg_num (int): Placement groups per pool (default 32).

Returns:
list[str]: List of created pool names.

Raises:
ExternalClusterPoolCreationFailed: If pool creation fails.

"""
if not pool_names:
raise ValueError("pool_names cannot be empty")

_, out, _ = self.exec_external_ceph_cmd(
cmd="ceph osd pool ls",
error_msg="Failed to list existing pools",
exception_class=ExternalClusterPoolCreationFailed,
)
existing_pools = out.strip().split("\n") if out.strip() else []

created_pools = []
for pool_name in pool_names:
if pool_name in existing_pools:
logger.info(f"Pool {pool_name} already exists, skipping creation")
created_pools.append(pool_name)
continue

logger.info(
f"Creating topology pool: {pool_name} (size={pool_size}, pg_num={pg_num})"
)

self.exec_external_ceph_cmd(
cmd=f"ceph osd pool create {pool_name} {pg_num} {pg_num} replicated",
error_msg=f"Failed to create pool {pool_name}",
exception_class=ExternalClusterPoolCreationFailed,
)

self.exec_external_ceph_cmd(
cmd=f"ceph osd pool set {pool_name} size {pool_size}",
error_msg=f"Failed to set size {pool_size} for pool {pool_name}",
exception_class=ExternalClusterPoolCreationFailed,
)

self.exec_external_ceph_cmd(
cmd=f"ceph osd pool application enable {pool_name} rbd",
error_msg=f"Failed to enable rbd for pool {pool_name}",
exception_class=ExternalClusterPoolCreationFailed,
)

logger.info(f"Created topology pool: {pool_name}")
created_pools.append(pool_name)

return created_pools


def get_exporter_script_from_configmap():
"""
Expand Down
3 changes: 3 additions & 0 deletions ocs_ci/ocs/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,9 @@
EXTERNAL_RGW_SC_NAME = "ocs-external-storagecluster-ceph-rgw"
CEPH_CLUSTER_NAME = "ocs-storagecluster-cephcluster"
REPLICA1_STORAGECLASS = "ocs-storagecluster-ceph-non-resilient-rbd"
DEFAULT_EXTERNAL_MODE_STORAGECLASS_NON_RESILIENT_RBD = (
"ocs-external-storagecluster-ceph-non-resilient-rbd"
)
ENDPOINTS = "Endpoints"
WEBHOOK = "ValidatingWebhookConfiguration"
ROOK_CEPH_WEBHOOK = "rook-ceph-webhook"
Expand Down
Loading
Loading