Skip to content

Commit

Permalink
[COST-4407] Add service account support
Browse files Browse the repository at this point in the history
* Add service account support as basic auth is becoming EOL
  • Loading branch information
chambridge committed Nov 3, 2023
1 parent bb865c2 commit 12f80f5
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 6 deletions.
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,8 @@ OCI_CREDENTIALS=OCI_PRIVATE_KEY
OCI_REGION=OCI_REGION
OCI_BUCKET_NAME=OCI_BUCKET_NAME
OCI_NAMESPACE=OCI_NAMESPACE

HCC_SERVICE_ACCOUNT_ID=SERVICE_ACCOUNT_ID
HCC_SERVICE_ACCOUNT_SECRET=SERVICE_ACCOUNT_SECRET
HCC_TOKEN_URL=https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token
HCC_TOKEN_SCOPE=api.console
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ The `make run-iqe` command by default will run the smoke tests. However, if you
- `overwrite` will generate a regular report with the invoice id
populated.
1. If `--insights-upload` is specified and pointing to a URL endpoint,
you must have `INSIGHTS_USER` and `INSIGHTS_PASSWORD` set in your
you must have `HCC_SERVICE_ACCOUNT_ID` and `HCC_SERVICE_ACCOUNT_SECRET` set in your
environment. Payloads for insights uploads will be split on a
per-file basis.
1. If `--static-report-file` is used start_date will default to first
Expand Down
10 changes: 7 additions & 3 deletions nise/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -558,15 +558,19 @@ def _validate_ocp_arguments(parser, options):
elif insights_upload is not None and not os.path.isdir(insights_upload):
insights_user = os.environ.get("INSIGHTS_USER")
insights_password = os.environ.get("INSIGHTS_PASSWORD")
hcc_service_account_id = os.environ.get("HCC_SERVICE_ACCOUNT_ID")
hcc_service_account_secret = os.environ.get("HCC_SERVICE_ACCOUNT_SECRET")
insights_account_id = os.environ.get("INSIGHTS_ACCOUNT_ID")
insights_org_id = os.environ.get("INSIGHTS_ORG_ID")
if (insights_account_id is None or insights_org_id is None) and (
insights_user is None or insights_password is None
if (
(insights_account_id is None or insights_org_id is None)
and (insights_user is None or insights_password is None)
and (hcc_service_account_id is None or hcc_service_account_secret is None)
):
msg = (
f"\n\t--insights-upload {insights_upload} was supplied as an argument\n"
"\tbut this directory does not exist locally. Attempting to upload to Ingress instead, but\n"
"\tthe environment must have \n\t\tINSIGHTS_USER and INSIGHTS_PASSWORD\n\tor\n"
"\tthe environment must have \n\t\\HCC_SERVICE_ACCOUNT_ID and HCC_SERVICE_ACCOUNT_SECRET\n\tor\n"
"\t\tINSIGHTS_ACCOUNT_ID and INSIGHTS_ORG_ID\n\tdefined when attempting an upload to Ingress.\n"
)
msg = msg.format("--insights-upload", insights_upload)
Expand Down
27 changes: 26 additions & 1 deletion nise/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,12 @@ def post_payload_to_ingest_service(insights_upload, local_path):
insights_org_id = os.environ.get("INSIGHTS_ORG_ID")
insights_user = os.environ.get("INSIGHTS_USER")
insights_password = os.environ.get("INSIGHTS_PASSWORD")
hcc_service_account_id = os.environ.get("HCC_SERVICE_ACCOUNT_ID")
hcc_service_account_secret = os.environ.get("HCC_SERVICE_ACCOUNT_SECRET")
hcc_token_url = os.environ.get(
"HCC_TOKEN_URL", "https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token"
)
hcc_token_scope = os.environ.get("HCC_TOKEN_SCOPE", "api.console")
content_type = "application/vnd.redhat.hccm.tar+tgz"
if os.path.isfile(local_path):
file_info = os.stat(local_path)
Expand All @@ -306,11 +312,30 @@ def post_payload_to_ingest_service(insights_upload, local_path):
headers=headers,
)

if insights_user and insights_password:
return requests.post(
insights_upload,
data={},
files={"file": ("payload.tar.gz", upload_file, content_type)},
auth=(insights_user, insights_password),
verify=False,
)

headers = {"Content-Type": "application/x-www-form-urlencoded"}
data = f"client_id={hcc_service_account_id}&client_secret={hcc_service_account_secret}"
data += f"&grant_type=client_credentials&scope={hcc_token_scope}"
token_resp = requests.post(hcc_token_url, data=data, headers=headers)
token = None
if token_resp.ok:
token_json = token_resp.json()
token = token_json.get("access_token")

headers = {"Authorization": f"Bearer {token}"}
return requests.post(
insights_upload,
data={},
files={"file": ("payload.tar.gz", upload_file, content_type)},
auth=(insights_user, insights_password),
headers=headers,
verify=False,
)

Expand Down
17 changes: 16 additions & 1 deletion tests/test_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ def test_post_payload_to_ingest_service_with_identity_header(self, mock_post):
@patch.dict(os.environ, {"INSIGHTS_USER": "12345", "INSIGHTS_PASSWORD": "54321"})
@patch("nise.report.requests.post")
def test_post_payload_to_ingest_service_with_basic_auth(self, mock_post):
"""Test that the identity header path is taken."""
"""Test that the basic auth path is taken."""
insights_user = os.environ.get("INSIGHTS_USER")
insights_password = os.environ.get("INSIGHTS_PASSWORD")

Expand All @@ -354,6 +354,21 @@ def test_post_payload_to_ingest_service_with_basic_auth(self, mock_post):
self.assertEqual(mock_post.call_args[1].get("auth"), auth)
self.assertNotIn("headers", mock_post.call_args[1])

@patch.dict(os.environ, {"HCC_SERVICE_ACCOUNT_ID": "12345", "HCC_SERVICE_ACCOUNT_SECRET": "54321"})
@patch("nise.report.requests.post")
def test_post_payload_to_ingest_service_with_service_account(self, mock_post):
"""Test that the service account path is taken."""
temp_file = NamedTemporaryFile(mode="w", delete=False)
headers = ["col1", "col2"]
data = [{"col1": "r1c1", "col2": "r1c2"}, {"col1": "r2c1", "col2": "r2c2"}]
_write_csv(temp_file.name, data, headers)

insights_upload = {}
data = {}

post_payload_to_ingest_service(insights_upload, temp_file.name)
self.assertEqual(mock_post.call_args[1].get("data"), data)

def test_defaulting_currency(self):
"""Test that if no currency is provide in options or static it defaults to USD."""
currency = None
Expand Down

0 comments on commit 12f80f5

Please sign in to comment.