Skip to content

Commit 96d3649

Browse files
authored
Fixed application packaging (missing util); Improved sample application testing. (#35)
1 parent 875e697 commit 96d3649

File tree

7 files changed

+52
-26
lines changed

7 files changed

+52
-26
lines changed

samples/Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
FROM python:3-slim
1+
FROM python:3.8-slim
22

33
RUN apt-get update
44

55
COPY requirements.txt /
6+
COPY util.py /
67
COPY {SAMPLE}.py /
78
COPY c8y_api /c8y_api
89

samples/build.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ mkdir -p "$DIST_DIR"
3535

3636
# copy & render sources
3737
cp ./requirements.txt "$BUILD_DIR"
38+
cp ./samples/util.py "$BUILD_DIR"
3839
cp "./samples/$NAME.py" "$BUILD_DIR"
3940
cp -r "./c8y_api" "$BUILD_DIR"
4041
sed -e "s/{VERSION}/$VERSION/g" ./samples/cumulocity.json > "$BUILD_DIR/cumulocity.json"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"isolation": "PER_TENANT",
3+
"requiredRoles": [
4+
"ROLE_OPTION_MANAGEMENT_READ",
5+
"ROLE_OPTION_MANAGEMENT_ADMIN"
6+
]
7+
}

samples/tenant_options.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44
# Use, reproduction, transfer, publication or disclosure is prohibited except
55
# as specifically provided for in your License Agreement with Software AG.
66

7-
from dotenv import load_dotenv
8-
97
from c8y_api.app import SimpleCumulocityApp
108

9+
from util import load_dotenv
1110

1211
load_dotenv()
1312
c8y = SimpleCumulocityApp()

samples/util.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@ def load_dotenv(sample_name: str | None = None):
3030
if os.path.exists(sample_env):
3131
print(f"Found custom .env extension: {sample_env}")
3232
with open(sample_env, 'r', encoding='UTF-8') as f:
33-
dotenv.load_dotenv(stream=f)
33+
dotenv.load_dotenv(stream=f, override=True)

tasks.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
def show_version(_):
1515
"""Print the module version.
1616
17-
This version string is infered from the last Git tag. A tagged HEAD
17+
This version string is inferred from the last Git tag. A tagged HEAD
1818
should resolve to a clean x.y.z version string.
1919
"""
2020
print(get_version())
@@ -61,37 +61,39 @@ def build_ms(c, sample, version='1.0.0'):
6161
@task(help={
6262
'sample': "Which sample to register."
6363
})
64-
def register_ms(c, sample):
64+
def register_ms(_, sample):
6565
"""Register a sample as microservice at Cumulocity."""
6666
ms_util.register_microservice(ms_util.format_sample_name(sample))
6767

6868

6969
@task(help={
7070
'sample': "Which sample to unregister."
7171
})
72-
def unregister_ms(c, sample):
72+
def unregister_ms(_, sample):
7373
"""Unregister a sample microservice from Cumulocity."""
7474
ms_util.unregister_microservice(ms_util.format_sample_name(sample))
7575

7676

7777
@task(help={
7878
'sample': "Which sample to register."
7979
})
80-
def get_credentials(c, sample):
80+
def get_credentials(_, sample):
8181
"""Unregister a sample microservice from Cumulocity."""
82-
user, password = ms_util.get_credentials(ms_util.format_sample_name(sample))
83-
print(f"Username: {user}\n"
82+
tenant, user, password = ms_util.get_credentials(ms_util.format_sample_name(sample))
83+
print(f"Tenant: {tenant}\n"
84+
f"Username: {user}\n"
8485
f"Password: {password}")
8586

8687

8788
@task(help={
8889
'sample': "Which sample to create a .env file for."
8990
})
90-
def create_env(c, sample):
91+
def create_env(_, sample):
9192
"""Create a sample specific .env-{sample_name} file using the
9293
credentials of a corresponding microservice registered at Cumulocity."""
9394
sample_name = ms_util.format_sample_name(sample)
94-
user, password = ms_util.get_credentials(sample_name)
95-
with open(f'.env-{sample_name}', 'w') as f:
96-
f.write(f"C8Y_USER={user}\n"
97-
f"C8Y_PASSWORD={password}\n")
95+
tenant, user, password = ms_util.get_credentials(sample_name)
96+
with open(f'.env-{sample_name}', 'w', encoding='UTF-8') as f:
97+
f.write(f'C8Y_TENANT={tenant}\n'
98+
f'C8Y_USER={user}\n'
99+
f'C8Y_PASSWORD={password}\n')

util/microservice_util.py

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
import zipfile
99

1010
from dotenv import load_dotenv
11+
from requests.auth import HTTPBasicAuth
1112

13+
from c8y_api import CumulocityApi
1214
from c8y_api.app import SimpleCumulocityApp
1315
from c8y_api.model import Application
1416

@@ -46,8 +48,8 @@ def register_microservice(sample_name: str):
4648

4749
# Read prepared binary .zip, extract manifest and parse
4850
zip_path = f'{_DIST_DIR}/samples/{sample_name}/{application_name}.zip'
49-
zip_file = zipfile.ZipFile(zip_path, 'r')
50-
manifest_json = json.loads(zip_file.read('cumulocity.json'))
51+
with zipfile.ZipFile(zip_path, 'r') as zip_file:
52+
manifest_json = json.loads(zip_file.read('cumulocity.json'))
5153

5254
# Create application stub in Cumulocity
5355
required_roles = manifest_json['requiredRoles']
@@ -57,7 +59,11 @@ def register_microservice(sample_name: str):
5759
required_roles=required_roles)
5860
app = app.create()
5961

60-
print(f"Microservice application '{application_name}' created. (ID {app.id})")
62+
# Subscribe to newly created microservice
63+
subscription_json = {'application': {'self': f'{c8y.base_url}/application/applications/{app.id}'}}
64+
c8y.post(f'/tenant/tenants/{c8y.tenant_id}/applications', json=subscription_json)
65+
66+
print(f"Microservice application '{application_name}' (ID {app.id}) created. Tenant '{c8y.tenant_id}' subscribed.")
6167

6268

6369
def unregister_microservice(sample_name: str):
@@ -82,8 +88,8 @@ def unregister_microservice(sample_name: str):
8288
app = c8y.applications.get_all(name=application_name)[0]
8389
# delete by ID
8490
app.delete()
85-
except IndexError:
86-
raise LookupError(f"Cannot retrieve information for an application named '{application_name}'.")
91+
except IndexError as e:
92+
raise LookupError(f"Cannot retrieve information for an application named '{application_name}'.") from e
8793

8894
print(f"Microservice application '{application_name}' (ID {app.id}) deleted.")
8995

@@ -107,12 +113,22 @@ def get_credentials(sample_name: str) -> (str, str):
107113
application_name = format_application_name(sample_name)
108114
load_dotenv()
109115

116+
c8y = SimpleCumulocityApp()
110117
try:
111-
c8y = SimpleCumulocityApp()
112118
# read applications by name, will throw IndexError if there is none
113119
app = c8y.applications.get_all(name=application_name)[0]
114-
# read bootstrap user details, parse and print
115-
user_json = c8y.get(f'/application/applications/{app.id}/bootstrapUser')
116-
return user_json['name'], user_json['password']
117-
except IndexError:
118-
raise LookupError(f"Cannot retrieve information for an application named '{application_name}'.")
120+
except IndexError as e:
121+
raise LookupError(f"Cannot retrieve information for an application named '{application_name}'.") from e
122+
123+
# read bootstrap user details
124+
bootstrap_user_json = c8y.get(f'/application/applications/{app.id}/bootstrapUser')
125+
# create bootstrap instance
126+
bootstrap_c8y = CumulocityApi(base_url=c8y.base_url,
127+
tenant_id=bootstrap_user_json['tenant'],
128+
auth=HTTPBasicAuth(bootstrap_user_json['name'], bootstrap_user_json['password']))
129+
# read all subscribed tenants, print first
130+
users_json = bootstrap_c8y.get('/application/currentApplication/subscriptions')['users']
131+
if not users_json: # empty users element?
132+
raise LookupError(f"Cannot retrieve subscribed tenants for application named '{application_name}'.")
133+
134+
return users_json[0]['tenant'], users_json[0]['name'], users_json[0]['password']

0 commit comments

Comments
 (0)