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

[SignalR] az signalr: Add subgroup command start/stop/restart replica, add/remove ip-rule #30058

Merged
merged 6 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
25 changes: 24 additions & 1 deletion src/azure-cli/azure/cli/command_modules/signalr/_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
# pylint: disable=line-too-long

import argparse
from azure.mgmt.signalr.models import UpstreamTemplate
from azure.mgmt.signalr.models import UpstreamTemplate, IPRule
from azure.cli.core.azclierror import InvalidArgumentValueError
from knack.log import get_logger
from knack.util import CLIError

Expand All @@ -24,3 +25,25 @@ def __call__(self, parser, namespace, values, option_string=None):
raise CLIError('usage error: {} KEY=VALUE [KEY=VALUE ...]'.format(option_string))
value = UpstreamTemplate(**kwargs)
super().__call__(parser, namespace, value, option_string)


class IPRuleTemplateUpdateAction(argparse._AppendAction):
# --ip-rule value="" action=""
def __call__(self, parser, namespace, values, option_string=None):
ipRuleValue = None
ipRuleAction = None
for item in values:
try:
key, value = item.split('=', 1)
if key == 'value':
ipRuleValue = value
elif key == 'action':
ipRuleAction = value
else:
raise InvalidArgumentValueError('usage error: {} KEY=VALUE [KEY=VALUE ...]'.format(option_string))
except ValueError:
raise InvalidArgumentValueError('usage error: {} KEY=VALUE [KEY=VALUE ...]'.format(option_string))
if ipRuleValue is None or ipRuleAction is None:
raise InvalidArgumentValueError('usage error: {} KEY=VALUE [KEY=VALUE ...]'.format(option_string))
value = IPRule(value=ipRuleValue, action=ipRuleAction)
super().__call__(parser, namespace, value, option_string)
50 changes: 50 additions & 0 deletions src/azure-cli/azure/cli/command_modules/signalr/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
short-summary: Manage network rules.
"""

helps['signalr network-rule ip-rule'] = """
type: group
short-summary: Manage SignalR Service IP rules.
"""

helps['signalr upstream'] = """
type: group
short-summary: Manage upstream settings.
Expand Down Expand Up @@ -228,6 +233,24 @@
az signalr network-rule update --public-network --connection-name MyPrivateEndpointConnection1 MyPrivateEndpointConnection2 -n MySignalR -g MyResourceGroup --deny ClientConnection
"""

helps['signalr network-rule ip-rule add'] = """
type: command
short-summary: Add IP rule to SignalR Service.
examples:
- name: Add IP rule
text: >
az signalr network-rule ip-rule add -n MySignalR -g MyResourceGroup --ip-rule value="10.0.0.24" action="Allow" --ip-rule value="192.168.0.0/24" action="Deny"
"""

helps['signalr network-rule ip-rule remove'] = """
type: command
short-summary: Remove IP rule from SignalR Service.
examples:
- name: Remove IP rule
text: >
az signalr network-rule ip-rule remove -n MySignalR -g MyResourceGroup --ip-rule value="10.0.0.24" action="Allow" --ip-rule value="192.168.0.0/24" action="Deny"
"""

helps['signalr identity assign'] = """
type: command
short-summary: Assign managed identity for SignalR Service.
Expand Down Expand Up @@ -300,6 +323,33 @@
short-summary: Show the detail of a custom certificate of SignalR Service.
"""

helps['signalr replica start'] = """
type: command
short-summary: Start a replica of SignalR Service.
examples:
- name: Start a replica
text: >
az signalr replica start --replica-name MyReplica --signalr-name MySignalR -g MyResourceGroup
"""

helps['signalr replica stop'] = """
type: command
short-summary: Stop a replica of SignalR Service.
examples:
- name: Stop a replica
text: >
az signalr replica stop --replica-name MyReplica --signalr-name MySignalR -g MyResourceGroup
"""

helps['signalr replica restart'] = """
type: command
short-summary: Restart a replica of SignalR Service.
examples:
- name: Restart a replica
text: >
az signalr replica restart --replica-name MyReplica --signalr-name MySignalR -g MyResourceGroup
"""

helps['signalr replica show'] = """
type: command
short-summary: Show the details of a replica
Expand Down
68 changes: 49 additions & 19 deletions src/azure-cli/azure/cli/command_modules/signalr/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,17 @@
get_three_state_flag
)
from ._actions import (
UpstreamTemplateAddAction
UpstreamTemplateAddAction,
IPRuleTemplateUpdateAction
)
from ._constants import (
SIGNALR_RESOURCE_TYPE,
SIGNALR_KEY_TYPE,
SIGNALR_SERVICE_MODE_TYPE
)

from ._validator import (
validate_ip_rule
)

logger = get_logger(__name__)

Expand All @@ -51,20 +54,27 @@ def load_arguments(self, _):
with self.argument_context('signalr create') as c:
c.argument('sku', help='The sku name of the signalr service. Allowed values: Premium_P1, Standard_S1, Free_F1')
c.argument('unit_count', help='The number of signalr service unit count', type=int)
c.argument('service_mode', help='The service mode which signalr service will be working on', choices=SIGNALR_SERVICE_MODE_TYPE)
c.argument('enable_message_logs', help='The switch for messaging logs which signalr service will generate or not', arg_type=get_three_state_flag())
c.argument('allowed_origins', options_list=['--allowed-origins', '-a'], nargs='*', help='space separated origins that should be allowed to make cross-origin calls (for example: http://example.com:12345). To allow all, use "*"')
c.argument('service_mode', help='The service mode which signalr service will be working on',
choices=SIGNALR_SERVICE_MODE_TYPE)
c.argument('enable_message_logs', help='The switch for messaging logs which signalr service will generate or not',
arg_type=get_three_state_flag())
c.argument('allowed_origins', options_list=['--allowed-origins', '-a'], nargs='*',
help='space separated origins that should be allowed to make cross-origin calls (for example: http://example.com:12345). To allow all, use "*"')

with self.argument_context('signalr update') as c:
c.argument('sku', help='The sku name of the signalr service. E.g. Standard_S1')
c.argument('unit_count', help='The number of signalr service unit count', type=int)
c.argument('service_mode', help='The service mode which signalr service will be working on', choices=SIGNALR_SERVICE_MODE_TYPE)
c.argument('enable_message_logs', help='The switch for messaging logs which signalr service will generate or not', arg_type=get_three_state_flag())
c.argument('allowed_origins', options_list=['--allowed-origins', '-a'], nargs='*', help='space separated origins that should be allowed to make cross-origin calls (for example: http://example.com:12345). To allow all, use "*"')
c.argument('service_mode', help='The service mode which signalr service will be working on',
choices=SIGNALR_SERVICE_MODE_TYPE)
c.argument('enable_message_logs', help='The switch for messaging logs which signalr service will generate or not',
arg_type=get_three_state_flag())
c.argument('allowed_origins', options_list=['--allowed-origins', '-a'], nargs='*',
help='space separated origins that should be allowed to make cross-origin calls (for example: http://example.com:12345). To allow all, use "*"')

for scope in ['signalr create', 'signalr update']:
with self.argument_context(scope, arg_group='Network Rule') as c:
c.argument('default_action', arg_type=get_enum_type(['Allow', 'Deny']), help='Default action to apply when no rule matches.', required=False)
c.argument('default_action', arg_type=get_enum_type(
['Allow', 'Deny']), help='Default action to apply when no rule matches.', required=False)

with self.argument_context('signalr key renew') as c:
c.argument('key_type', help='The name of access key to regenerate', choices=SIGNALR_KEY_TYPE)
Expand All @@ -73,37 +83,51 @@ def load_arguments(self, _):
c.argument('signalr_name', id_part=None)

with self.argument_context('signalr cors add') as c:
c.argument('allowed_origins', options_list=['--allowed-origins', '-a'], nargs='*', help='space separated origins that should be allowed to make cross-origin calls (for example: http://example.com:12345). To allow all, use "*"')
c.argument('allowed_origins', options_list=['--allowed-origins', '-a'], nargs='*',
help='space separated origins that should be allowed to make cross-origin calls (for example: http://example.com:12345). To allow all, use "*"')

with self.argument_context('signalr cors remove') as c:
c.argument('allowed_origins', options_list=['--allowed-origins', '-a'], nargs='*', help='space separated origins that should be allowed to make cross-origin calls (for example: http://example.com:12345). To allow all, use "*"')
c.argument('allowed_origins', options_list=['--allowed-origins', '-a'], nargs='*',
help='space separated origins that should be allowed to make cross-origin calls (for example: http://example.com:12345). To allow all, use "*"')

with self.argument_context('signalr cors update') as c:
c.argument('allowed_origins', options_list=['--allowed-origins', '-a'], nargs='*', help='space separated origins that should be allowed to make cross-origin calls (for example: http://example.com:12345). To allow all, use "*"')
c.argument('allowed_origins', options_list=['--allowed-origins', '-a'], nargs='*',
help='space separated origins that should be allowed to make cross-origin calls (for example: http://example.com:12345). To allow all, use "*"')

with self.argument_context('signalr cors list') as c:
c.argument('signalr_name', id_part=None)

# Network Rule
with self.argument_context('signalr network-rule update') as c:
c.argument('connection_name', nargs='*', help='Space-separeted list of private endpoint connection name.', required=False, arg_group='Private Endpoint Connection')
c.argument('public_network', arg_type=get_three_state_flag(), help='Set rules for public network.', required=False, arg_group='Public Network')
c.argument('allow', nargs='*', help='The allowed virtual network rule. Space-separeted list of scope to assign. Allowed values: ClientConnection, ServerConnection, RESTAPI', type=SignalRRequestType, required=False)
c.argument('deny', nargs='*', help='The denied virtual network rule. Space-separeted list of scope to assign. Allowed values: ClientConnection, ServerConnection, RESTAPI', type=SignalRRequestType, required=False)
c.argument('connection_name', nargs='*', help='Space-separeted list of private endpoint connection name.',
required=False, arg_group='Private Endpoint Connection')
c.argument('public_network', arg_type=get_three_state_flag(),
help='Set rules for public network.', required=False, arg_group='Public Network')
c.argument('allow', nargs='*', help='The allowed virtual network rule. Space-separeted list of scope to assign. Allowed values: ClientConnection, ServerConnection, RESTAPI',
type=SignalRRequestType, required=False)
c.argument('deny', nargs='*', help='The denied virtual network rule. Space-separeted list of scope to assign. Allowed values: ClientConnection, ServerConnection, RESTAPI',
type=SignalRRequestType, required=False)

for scope in ['signalr network-rule ip-rule add', 'signalr network-rule ip-rule remove']:
with self.argument_context(scope, validator=validate_ip_rule) as c:
c.argument('ip_rule', action=IPRuleTemplateUpdateAction, nargs='*',
help='The IP rule for the hub.', required=True)

with self.argument_context('signalr network-rule list') as c:
c.argument('signalr_name', id_part=None)

# Upstream Settings
with self.argument_context('signalr upstream update') as c:
c.argument('template', action=UpstreamTemplateAddAction, nargs='+', help='Template item for upstream settings. Use key=value pattern to set properties. Supported keys are "url-template", "hub-pattern", "event-pattern", "category-pattern".')
c.argument('template', action=UpstreamTemplateAddAction, nargs='+',
help='Template item for upstream settings. Use key=value pattern to set properties. Supported keys are "url-template", "hub-pattern", "event-pattern", "category-pattern".')

with self.argument_context('signalr upstream list') as c:
c.argument('signalr_name', id_part=None)

# Managed Identity
with self.argument_context('signalr identity assign') as c:
c.argument('identity', help="Assigns managed identities to the service. Use '[system]' to refer to the system-assigned identity or a resource ID to refer to a user-assigned identity. You can only assign either on of them.")
c.argument(
'identity', help="Assigns managed identities to the service. Use '[system]' to refer to the system-assigned identity or a resource ID to refer to a user-assigned identity. You can only assign either on of them.")

# Custom Domain
for scope in ['signalr custom-domain update',
Expand Down Expand Up @@ -143,7 +167,10 @@ def load_arguments(self, _):
for scope in ['signalr replica create',
'signalr replica list',
'signalr replica delete',
'signalr replica show']:
'signalr replica show',
'signalr replica start',
'signalr replica stop',
'signalr replica restart']:
with self.argument_context(scope) as c:
c.argument('sku', help='The sku name of the replica. Currently allowed values: Premium_P1')
c.argument('unit_count', help='The number of signalr service unit count', type=int)
Expand All @@ -155,6 +182,9 @@ def load_arguments(self, _):
c.argument('signalr_name', signalr_name_type, id_part=None)

for scope in ['signalr replica show',
'signalr replica start',
'signalr replica stop',
'signalr replica restart',
'signalr replica delete']:
with self.argument_context(scope) as c:
c.argument('signalr_name', signalr_name_type)
11 changes: 11 additions & 0 deletions src/azure-cli/azure/cli/command_modules/signalr/_validator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
# pylint: disable=line-too-long
from azure.cli.core.azclierror import RequiredArgumentMissingError


def validate_ip_rule(namespace):
if not namespace.ip_rule:
raise RequiredArgumentMissingError('IP rule should be set.')
13 changes: 11 additions & 2 deletions src/azure-cli/azure/cli/command_modules/signalr/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ def load_command_table(self, _):
g.command('list', 'list_network_rules')
g.command('update', 'update_network_rules')

with self.command_group('signalr network-rule ip-rule', signalr_network_utils) as g:
g.command('add', 'add_ip_rule')
g.command('remove', 'remove_ip_rule')

with self.command_group('signalr upstream', signalr_upstream_utils) as g:
g.command('list', 'signalr_upstream_list')
g.command('update', 'signalr_upstream_update')
Expand All @@ -101,18 +105,23 @@ def load_command_table(self, _):
g.show_command('show', 'custom_domain_show', exception_handler=empty_on_404)
g.command('create', 'custom_domain_create')
g.command('delete', 'custom_domain_delete')
g.generic_update_command('update', getter_name='get_custom_domain', setter_name='set_custom_domain', custom_func_name='update', custom_func_type=signalr_custom_domain_utils)
g.generic_update_command('update', getter_name='get_custom_domain', setter_name='set_custom_domain',
custom_func_name='update', custom_func_type=signalr_custom_domain_utils)
g.command('list', 'custom_domain_list')

with self.command_group('signalr custom-certificate', signalr_custom_certificate_utils) as g:
g.show_command('show', 'custom_certificate_show', exception_handler=empty_on_404)
g.command('create', 'custom_certificate_create')
g.command('delete', 'custom_certificate_delete')
g.generic_update_command('update', getter_name='get_custom_certificate', setter_name='set_custom_certificate', custom_func_name='update', custom_func_type=signalr_custom_certificate_utils)
g.generic_update_command('update', getter_name='get_custom_certificate', setter_name='set_custom_certificate',
custom_func_name='update', custom_func_type=signalr_custom_certificate_utils)
g.command('list', 'custom_certificate_list')

with self.command_group('signalr replica', signalr_replica_utils) as g:
g.command('create', 'signalr_replica_create')
g.command('list', 'signalr_replica_list')
g.show_command('show', 'signalr_replica_show', exception_handler=empty_on_404)
g.command('start', 'signalr_replica_start', exception_handler=empty_on_404)
g.command('stop', 'signalr_replica_stop', exception_handler=empty_on_404)
g.command('restart', 'signalr_replica_restart', exception_handler=empty_on_404)
g.show_command('delete', 'signalr_replica_delete')
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,13 @@ signalr custom-domain update:
certificate_resource_id:
rule_exclusions:
- option_length_too_long
signalr replica start:
rule_exclusions:
- missing_command_test_coverage
signalr replica stop:
rule_exclusions:
- missing_command_test_coverage
signalr replica restart:
rule_exclusions:
- missing_command_test_coverage
...
14 changes: 14 additions & 0 deletions src/azure-cli/azure/cli/command_modules/signalr/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,17 @@ def update_network_rules(client, signalr_name, resource_group_name, public_netwo
def list_network_rules(client, signalr_name, resource_group_name):
resource = client.get(resource_group_name, signalr_name)
return resource.network_ac_ls


def add_ip_rule(client, signalr_name, resource_group_name, ip_rule):
resource = client.get(resource_group_name, signalr_name)
network_acl = resource.network_ac_ls
network_acl.ip_rules.extend(ip_rule)
return client.begin_update(resource_group_name, signalr_name, SignalRResource(location=resource.location, network_ac_ls=network_acl))


def remove_ip_rule(client, signalr_name, resource_group_name, ip_rule):
resource = client.get(resource_group_name, signalr_name)
network_acl = resource.network_ac_ls
network_acl.ip_rules = [rule for rule in network_acl.ip_rules if rule not in ip_rule]
return client.begin_update(resource_group_name, signalr_name, SignalRResource(location=resource.location, network_ac_ls=network_acl))
14 changes: 14 additions & 0 deletions src/azure-cli/azure/cli/command_modules/signalr/replica.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@ def signalr_replica_show(client: SignalRReplicasOperations, signalr_name, replic
return client.get(resource_group_name=resource_group_name, resource_name=signalr_name, replica_name=replica_name)


def signalr_replica_start(client: SignalRReplicasOperations, signalr_name, replica_name, resource_group_name):
parameter = Replica(location=None, resource_stopped=False)
return client.begin_update(resource_group_name=resource_group_name, resource_name=signalr_name, replica_name=replica_name, parameters=parameter)


def signalr_replica_stop(client: SignalRReplicasOperations, signalr_name, replica_name, resource_group_name):
parameter = Replica(location=None, resource_stopped=True)
return client.begin_update(resource_group_name=resource_group_name, resource_name=signalr_name, replica_name=replica_name, parameters=parameter)


def signalr_replica_restart(client: SignalRReplicasOperations, signalr_name, replica_name, resource_group_name):
return client.begin_restart(resource_group_name=resource_group_name, resource_name=signalr_name, replica_name=replica_name)


def signalr_replica_delete(client: SignalRReplicasOperations, signalr_name, replica_name, resource_group_name):
return client.delete(resource_group_name=resource_group_name, resource_name=signalr_name, replica_name=replica_name)

Expand Down
Loading