Skip to content

Commit 187159b

Browse files
authored
[load] Adding support for creating and managing Schedule in load test resource using CLI (#8540)
* Adding commands for scheduling * added list schedule command * initial tests for scheduling * Updated tests * Enhancing test cases for schedule * Optimizing utils and addressing PR comments * Adding invalid test cases * Addressing PR comments * linting and styling * test cases and recordings updated * nit * Updating version * nit * Addressing PR comments and issues after bug bash * Fixes after running githooks * removed datetime.UTC as not supported in python 3.9
1 parent fac4ffe commit 187159b

23 files changed

Lines changed: 5417 additions & 17 deletions

src/load/HISTORY.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
33
Release History
44
===============
5+
1.8.0
6+
++++++
7+
* Add commands for creating and managing schedule triggers using CLI.
58

69
1.7.0
710
++++++

src/load/azext_load/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ def load_command_table(self, args):
1818
from azext_load.commands import load_command_table
1919
from azext_load.data_plane.load_test.commands import load_test_commands
2020
from azext_load.data_plane.load_test_run.commands import load_test_run_commands
21+
from azext_load.data_plane.load_trigger.commands import load_trigger_schedule_commands
2122
from azure.cli.core.aaz import load_aaz_command_table
2223
try:
2324
from . import aaz
@@ -32,18 +33,21 @@ def load_command_table(self, args):
3233
load_command_table(self, args)
3334
load_test_commands(self, args)
3435
load_test_run_commands(self, args)
36+
load_trigger_schedule_commands(self, args)
3537
return self.command_table
3638

3739
def load_arguments(self, command):
3840
from azext_load._params import load_arguments
3941
from azext_load.data_plane.params import load_arguments as load_common_arguments
4042
from azext_load.data_plane.load_test.params import load_arguments as load_test_arguments
4143
from azext_load.data_plane.load_test_run.params import load_arguments as load_test_run_arguments
44+
from azext_load.data_plane.load_trigger.params import load_arguments as load_trigger_schedule_arguments
4245

4346
load_arguments(self, command)
4447
load_common_arguments(self, command)
4548
load_test_arguments(self, command)
4649
load_test_run_arguments(self, command)
50+
load_trigger_schedule_arguments(self, command)
4751

4852

4953
COMMAND_LOADER_CLS = LoadCommandsLoader

src/load/azext_load/_help.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
from azext_load.data_plane.help import helps as data_common_helps
1313
from azext_load.data_plane.load_test.help import helps as data_load_test_helps
1414
from azext_load.data_plane.load_test_run.help import helps as data_load_test_run_helps
15+
from azext_load.data_plane.load_trigger.help import helps as data_load_trigger_helps
1516

1617
helps.update(data_common_helps)
1718
helps.update(data_load_test_helps)
1819
helps.update(data_load_test_run_helps)
20+
helps.update(data_load_trigger_helps)

src/load/azext_load/data_plane/help.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,19 @@
8484
short-summary: Command group to retrieve load test run metrics.
8585
long-summary: Command group to retrieve load test run metrics with list, get-namespaces, get-definitions, get-dimension.
8686
""" + _common_params
87+
88+
helps[
89+
"load trigger"
90+
] = """
91+
type: group
92+
short-summary: Command group to manage trigger.
93+
long-summary: Command group to manage triggers. Currently the only supported trigger type is schedule.
94+
""" + _common_params
95+
96+
helps[
97+
"load trigger schedule"
98+
] = """
99+
type: group
100+
short-summary: Command group to manage schedule triggers.
101+
long-summary: Command group to manage schedule triggers.
102+
""" + _common_params
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# --------------------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for license information.
4+
# --------------------------------------------------------------------------------------------
5+
6+
__path__ = __import__("pkgutil").extend_path(__path__, __name__)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# --------------------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for license information.
4+
# --------------------------------------------------------------------------------------------
5+
6+
from azure.cli.core.commands import CliCommandType
7+
8+
admin_custom_sdk = CliCommandType(
9+
operations_tmpl="azext_load.data_plane.load_trigger.custom#{}"
10+
)
11+
12+
13+
def load_trigger_schedule_commands(self, _):
14+
with self.command_group(
15+
"load trigger", custom_command_type=admin_custom_sdk, is_preview=True
16+
):
17+
pass
18+
19+
with self.command_group(
20+
"load trigger schedule", custom_command_type=admin_custom_sdk, is_preview=True
21+
) as g:
22+
g.custom_command("create", "create_trigger_schedule")
23+
g.custom_command("update", "update_trigger_schedule")
24+
g.custom_command("delete", "delete_trigger_schedule", confirmation=True)
25+
g.custom_show_command("show", "get_trigger_schedule")
26+
g.custom_command("pause", "pause_trigger_schedule")
27+
g.custom_command("enable", "enable_trigger_schedule")
28+
g.custom_command("list", "list_trigger_schedules")
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
# --------------------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for license information.
4+
# --------------------------------------------------------------------------------------------
5+
6+
# pylint: disable=line-too-long
7+
8+
from azure.core.exceptions import ResourceNotFoundError
9+
from azure.cli.core.azclierror import InvalidArgumentValueError, ValidationError
10+
from knack.log import get_logger
11+
from azext_load.data_plane.utils.utils import (
12+
get_admin_data_plane_client)
13+
from azext_load.vendored_sdks.loadtesting.models import (_models as models, _enums as enums)
14+
from azext_load.data_plane.load_trigger import utils
15+
16+
logger = get_logger(__name__)
17+
18+
19+
def create_trigger_schedule(
20+
cmd,
21+
load_test_resource,
22+
resource_group_name=None,
23+
trigger_id=None,
24+
description=None,
25+
display_name=None,
26+
trigger_start_date_time=None,
27+
recurrence_type=None,
28+
recurrence_interval=None,
29+
recurrence_index=None,
30+
recurrence_cron_expression=None,
31+
recurrence_dates_in_month=None,
32+
recurrence_week_days=None,
33+
end_after_occurrence=None,
34+
end_after_date_time=None,
35+
test_ids=None,
36+
):
37+
client = get_admin_data_plane_client(cmd, load_test_resource, resource_group_name)
38+
logger.info("Creating schedule trigger.")
39+
try:
40+
client.get_trigger(trigger_id)
41+
msg = "Trigger schedule with id: {} already exists.".format(trigger_id)
42+
logger.error(msg)
43+
raise InvalidArgumentValueError(msg)
44+
except ResourceNotFoundError:
45+
pass
46+
recurrence_end_body = utils.get_recurrence_end_body(
47+
end_after_occurrence,
48+
end_after_date_time,
49+
)
50+
logger.debug("Recurrence end object: %s", recurrence_end_body)
51+
recurrence_body = utils.get_recurrence_body(
52+
recurrence_type,
53+
recurrence_interval,
54+
recurrence_index,
55+
recurrence_cron_expression,
56+
recurrence_dates_in_month,
57+
recurrence_week_days,
58+
recurrence_end_body,
59+
)
60+
logger.debug("Recurrence object: %s", recurrence_body)
61+
trigger_body = models.ScheduleTestsTrigger(
62+
test_ids=test_ids,
63+
recurrence=recurrence_body,
64+
start_date_time=trigger_start_date_time,
65+
state=enums.TriggerState.ACTIVE,
66+
display_name=display_name,
67+
description=description,
68+
)
69+
logger.debug("Trigger schedule body: %s", trigger_body)
70+
try:
71+
response = client.create_or_update_trigger(trigger_id=trigger_id, body=trigger_body)
72+
logger.debug("Created trigger schedule: %s", response)
73+
logger.info("Creating trigger schedule completed")
74+
return response.as_dict()
75+
except Exception:
76+
logger.error("Error occurred while creating schedule trigger.")
77+
raise
78+
79+
80+
def update_trigger_schedule(
81+
cmd,
82+
load_test_resource,
83+
trigger_id,
84+
resource_group_name=None,
85+
description=None,
86+
display_name=None,
87+
trigger_start_date_time=None,
88+
recurrence_type=None,
89+
recurrence_interval=None,
90+
recurrence_index=None,
91+
recurrence_cron_expression=None,
92+
recurrence_dates_in_month=None,
93+
recurrence_week_days=None,
94+
end_after_occurrence=None,
95+
end_after_date_time=None,
96+
test_ids=None,
97+
):
98+
client = get_admin_data_plane_client(cmd, load_test_resource, resource_group_name)
99+
logger.info("Updating schedule trigger with id: %s", trigger_id)
100+
existing_trigger_schedule: models.ScheduleTestsTrigger = None
101+
try:
102+
existing_trigger_schedule = client.get_trigger(trigger_id)
103+
except ResourceNotFoundError:
104+
msg = "Schedule trigger with id: {} does not exists.".format(trigger_id)
105+
logger.debug(msg)
106+
raise InvalidArgumentValueError(msg)
107+
logger.debug("Existing schedule trigger: %s", existing_trigger_schedule)
108+
recurrence_end_body = utils.get_recurrence_end_body(
109+
end_after_occurrence,
110+
end_after_date_time,
111+
existing_trigger_schedule.recurrence.recurrence_end if existing_trigger_schedule.recurrence else None
112+
)
113+
logger.debug("Recurrence end object: %s", recurrence_end_body)
114+
recurrence_body = utils.get_recurrence_body_for_update(
115+
recurrence_type,
116+
recurrence_interval,
117+
recurrence_index,
118+
recurrence_cron_expression,
119+
recurrence_dates_in_month,
120+
recurrence_week_days,
121+
recurrence_end_body,
122+
existing_trigger_schedule.recurrence
123+
)
124+
logger.debug("Recurrence object: %s", recurrence_body)
125+
new_trigger_body = models.ScheduleTestsTrigger(
126+
test_ids=test_ids,
127+
recurrence=recurrence_body,
128+
start_date_time=trigger_start_date_time,
129+
display_name=display_name,
130+
description=description,
131+
)
132+
new_trigger_body.state = existing_trigger_schedule.state
133+
logger.debug("Schedule trigger body to be sent for update: %s", new_trigger_body)
134+
try:
135+
response = client.create_or_update_trigger(trigger_id=trigger_id, body=new_trigger_body)
136+
logger.debug("Updated schedule trigger: %s", response)
137+
logger.info("Updating schedule trigger completed")
138+
return response.as_dict()
139+
except Exception:
140+
logger.error("Error occurred while updating schedule trigger.")
141+
raise
142+
143+
144+
def delete_trigger_schedule(
145+
cmd,
146+
load_test_resource,
147+
trigger_id,
148+
resource_group_name=None,
149+
):
150+
logger.info(
151+
"Deleting schedule trigger with id: %s", trigger_id
152+
)
153+
client = get_admin_data_plane_client(cmd, load_test_resource, resource_group_name)
154+
client.delete_trigger(trigger_id)
155+
logger.info("Deleting schedule trigger completed.")
156+
157+
158+
def get_trigger_schedule(
159+
cmd,
160+
load_test_resource,
161+
trigger_id,
162+
resource_group_name=None,
163+
):
164+
logger.info(
165+
"Getting schedule trigger with id: %s", trigger_id
166+
)
167+
client = get_admin_data_plane_client(cmd, load_test_resource, resource_group_name)
168+
response = client.get_trigger(trigger_id)
169+
logger.debug("Fetched schedule trigger: %s", response)
170+
return response.as_dict()
171+
172+
173+
def pause_trigger_schedule(
174+
cmd,
175+
load_test_resource,
176+
trigger_id,
177+
resource_group_name=None,
178+
):
179+
logger.info(
180+
"Pausing schedule trigger with id: %s", trigger_id
181+
)
182+
client = get_admin_data_plane_client(cmd, load_test_resource, resource_group_name)
183+
existing_trigger_schedule: models.ScheduleTestsTrigger = None
184+
try:
185+
existing_trigger_schedule = client.get_trigger(trigger_id)
186+
except ResourceNotFoundError:
187+
msg = "Schedule trigger with id: {} does not exists.".format(trigger_id)
188+
logger.debug(msg)
189+
raise InvalidArgumentValueError(msg)
190+
logger.debug("Existing schedule trigger object: %s", existing_trigger_schedule)
191+
if existing_trigger_schedule.state == enums.TriggerState.ACTIVE:
192+
existing_trigger_schedule.state = enums.TriggerState.PAUSED
193+
response = client.create_or_update_trigger(trigger_id=trigger_id, body=existing_trigger_schedule)
194+
logger.debug("Paused schedule trigger: %s", response)
195+
return response.as_dict()
196+
if existing_trigger_schedule.state == enums.TriggerState.COMPLETED:
197+
msg = "Schedule trigger with id: {} is already completed. A completed schedule cannot be paused.".format(trigger_id)
198+
logger.error(msg)
199+
raise ValidationError(msg)
200+
logger.warning("Schedule trigger is not active. It is in %s state. Enable the schedule before performing pause action.", existing_trigger_schedule.state.value)
201+
202+
203+
def enable_trigger_schedule(
204+
cmd,
205+
load_test_resource,
206+
trigger_id,
207+
resource_group_name=None,
208+
):
209+
logger.info(
210+
"Enabling schedule trigger with id: %s", trigger_id
211+
)
212+
client = get_admin_data_plane_client(cmd, load_test_resource, resource_group_name)
213+
existing_trigger_schedule: models.ScheduleTestsTrigger = None
214+
try:
215+
existing_trigger_schedule = client.get_trigger(trigger_id)
216+
except ResourceNotFoundError:
217+
msg = "Schedule trigger with id: {} does not exists.".format(trigger_id)
218+
logger.debug(msg)
219+
raise InvalidArgumentValueError(msg)
220+
logger.debug("Existing trigger object: %s", existing_trigger_schedule)
221+
if existing_trigger_schedule.state != enums.TriggerState.COMPLETED:
222+
existing_trigger_schedule.state = enums.TriggerState.ACTIVE
223+
response = client.create_or_update_trigger(trigger_id=trigger_id, body=existing_trigger_schedule)
224+
logger.debug("Enabled schedule trigger: %s", response)
225+
return response.as_dict()
226+
msg = "Schedule trigger with id: {} is already completed. A completed schedule cannot be enabled.".format(trigger_id)
227+
logger.debug(msg)
228+
raise ValidationError(msg)
229+
230+
231+
def list_trigger_schedules(
232+
cmd,
233+
load_test_resource,
234+
resource_group_name=None,
235+
trigger_states=None,
236+
test_ids=None,
237+
):
238+
logger.info("Listing schedule triggers.")
239+
client = get_admin_data_plane_client(cmd, load_test_resource, resource_group_name)
240+
if trigger_states:
241+
trigger_states = ",".join(trigger_states)
242+
if test_ids:
243+
test_ids = ",".join(test_ids)
244+
logger.info("Schedule trigger states: %s", trigger_states)
245+
response_list = client.list_trigger(test_ids=test_ids, states=trigger_states)
246+
logger.debug("Fetched list of schedule triggers: %s", response_list)
247+
return [response.as_dict() for response in response_list]

0 commit comments

Comments
 (0)