Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only use EC2 creds from our project. Clean up after use. #892

Merged
merged 14 commits into from
Mar 20, 2025
Merged
123 changes: 74 additions & 49 deletions Tests/iaas/mandatory-services/mandatory-iaas-services.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,20 @@
"""

import argparse
import boto3
from collections import Counter
import json
import logging
import os
import re
import sys
import uuid

import boto3
import openstack


TESTCONTNAME = "scs-test-container"
EC2MARKER = "TmpMandSvcTest"

logger = logging.getLogger(__name__)
mandatory_services = ["compute", "identity", "image", "network",
Expand Down Expand Up @@ -114,32 +116,48 @@ def s3_from_env(creds, fieldnm, env, prefix=""):


def s3_from_ostack(creds, conn, endpoint):
"Set creds from openstack swift/keystone"
"""Set creds from openstack swift/keystone
Returns credential ID *if* an ec2 credential was created,
None otherwise."""
rgx = re.compile(r"^(https*://[^/]*)/")
match = rgx.match(endpoint)
if match:
creds["HOST"] = match.group(1)
# Use first ec2 cred if one exists
# Use first ec2 cred that matches the project (if one exists)
project_id = conn.identity.get_project_id()
ec2_creds = [cred for cred in conn.identity.credentials()
if cred.type == "ec2"]
if len(ec2_creds):
# FIXME: Assume cloud is not evil
ec2_dict = eval(ec2_creds[0].blob, {"null": None})
creds["AK"] = ec2_dict["access"]
creds["SK"] = ec2_dict["secret"]
if cred.type == "ec2" and cred.project_id == project_id]
found_ec2 = None
for cred in ec2_creds:
try:
ec2_dict = json.loads(cred.blob)
except Exception:
logger.warning(f"unable to parse credential {cred!r}", exc_info=True)
continue
# Clean up old EC2 creds and jump over
if ec2_dict.get("owner") == EC2MARKER:
logger.debug(f"Removing leftover credential {ec2_dict['access']}")
conn.identity.delete_credential(cred)
continue
found_ec2 = ec2_dict
if found_ec2:
creds["AK"] = found_ec2["access"]
creds["SK"] = found_ec2["secret"]
return
# Generate keyid and secret
ak = uuid.uuid4().hex
sk = uuid.uuid4().hex
blob = f'{{"access": "{ak}", "secret": "{sk}"}}'
blob = f'{{"access": "{ak}", "secret": "{sk}", "owner": "{EC2MARKER}"}}'
try:
conn.identity.create_credential(type="ec2", blob=blob,
user_id=conn.current_user_id,
project_id=conn.current_project_id)
creds["AK"] = ak
creds["SK"] = sk
except BaseException as exc:
logger.warning(f"ec2 creds creation failed: {exc!s}")
crd = conn.identity.create_credential(type="ec2", blob=blob,
user_id=conn.current_user_id,
project_id=conn.current_project_id)
except BaseException:
logger.warning("ec2 creds creation failed", exc_info=True)
return
creds["AK"] = ak
creds["SK"] = sk
return crd.id


def check_for_s3_and_swift(conn: openstack.connection.Connection, s3_credentials=None):
Expand Down Expand Up @@ -170,38 +188,45 @@ def check_for_s3_and_swift(conn: openstack.connection.Connection, s3_credentials
)
return 1
# Get S3 endpoint (swift) and ec2 creds from OpenStack (keystone)
s3_from_ostack(s3_creds, conn, endpoint)
# Overrides (var names are from libs3, in case you wonder)
s3_from_env(s3_creds, "HOST", "S3_HOSTNAME", "https://")
s3_from_env(s3_creds, "AK", "S3_ACCESS_KEY_ID")
s3_from_env(s3_creds, "SK", "S3_SECRET_ACCESS_KEY")

# This is to be used for local debugging purposes ONLY
# logger.info(f"using credentials {s3_creds}")

s3 = s3_conn(s3_creds, conn)
s3_buckets = list_s3_buckets(s3) or create_bucket(s3, TESTCONTNAME)
if not s3_buckets:
raise RuntimeError("failed to create S3 bucket")

# If we got till here, s3 is working, now swift
swift_containers = list_containers(conn)
# if not swift_containers:
# swift_containers = create_container(conn, TESTCONTNAME)
result = 0
if Counter(s3_buckets) != Counter(swift_containers):
logger.error("S3 buckets and Swift Containers differ:\n"
f"S3: {sorted(s3_buckets)}\nSW: {sorted(swift_containers)}")
result = 1
else:
logger.info("SUCCESS: S3 and Swift exist and agree")
# Clean up
# FIXME: Cleanup created EC2 credential
# if swift_containers == [TESTCONTNAME]:
# del_container(conn, TESTCONTNAME)
# Cleanup created S3 bucket
if s3_buckets == [TESTCONTNAME]:
del_bucket(s3, TESTCONTNAME)
try:
ec2_cred = s3_from_ostack(s3_creds, conn, endpoint)
# Overrides (var names are from libs3, in case you wonder)
s3_from_env(s3_creds, "HOST", "S3_HOSTNAME", "https://")
s3_from_env(s3_creds, "AK", "S3_ACCESS_KEY_ID")
s3_from_env(s3_creds, "SK", "S3_SECRET_ACCESS_KEY")

# This is to be used for local debugging purposes ONLY
# logger.info(f"using credentials {s3_creds}")

s3 = s3_conn(s3_creds, conn)
s3_buckets = list_s3_buckets(s3) or create_bucket(s3, TESTCONTNAME)
if not s3_buckets:
raise RuntimeError("failed to create S3 bucket")

# If we got till here, s3 is working, now swift
swift_containers = list_containers(conn)
# if not swift_containers:
# swift_containers = create_container(conn, TESTCONTNAME)
result = 0
# Compare number of buckets/containers
# FIXME: Could compare list of sorted names
if Counter(s3_buckets) != Counter(swift_containers):
logger.error("S3 buckets and Swift Containers differ:\n"
f"S3: {sorted(s3_buckets)}\nSW: {sorted(swift_containers)}")
result = 1
else:
logger.info("SUCCESS: S3 and Swift exist and agree")
# No need to clean up swift container, as we did not create one
# (If swift and S3 agree, there will be a S3 bucket that we clean up with S3.)
# if swift_containers == [TESTCONTNAME]:
# del_container(conn, TESTCONTNAME)
# Cleanup created S3 bucket
if s3_buckets == [TESTCONTNAME]:
del_bucket(s3, TESTCONTNAME)
# Clean up ec2 cred IF we created one
finally:
if ec2_cred:
conn.identity.delete_credential(ec2_cred)
return result


Expand Down