Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
403f4b6
Deprecate 'iotcentral' and use 'iot central'
Mar 20, 2020
4a4c31d
lint
Mar 24, 2020
36b2bff
Merge branch 'dev' into rodelga/iotcentral/deprecate
Mar 24, 2020
6c54206
Update help sku value
Mar 24, 2020
41ee366
Use show_custom_command for 'show' command
Mar 24, 2020
a1ae112
Update method comments
Mar 24, 2020
b9a4dd2
linting, run tests
Mar 24, 2020
84db750
record tests
Mar 24, 2020
da51031
re-run tests
Mar 25, 2020
09d1ad6
run tests
Mar 26, 2020
c4d97e4
update test_iot_hub.yaml
fengzhou-msft Mar 27, 2020
8cd1bd6
revert test_iot_hub.yaml to previous PR commit
fengzhou-msft Mar 27, 2020
8fa8b68
Bump version
Mar 27, 2020
0562501
Merge branch 'rodelga/iotcentral/deprecate' of https://github.com/r-d…
Mar 27, 2020
d33b89f
resolve merge conflicts
Mar 27, 2020
d3fc96a
fix history
Mar 27, 2020
51c2ead
remove expiration date
Mar 27, 2020
6f4e827
sync with master
Apr 10, 2020
a5cd185
sync with dev
Apr 10, 2020
82395cb
Merge branch 'rodelga/iotcentral/deprecate' of https://github.com/r-d…
Apr 10, 2020
d588253
run test
Apr 13, 2020
6c42022
Remove History comments
Apr 14, 2020
3443795
Add confirmation message for deleteing an application
Apr 15, 2020
56cd739
Revert confirmation
Apr 15, 2020
5d5a3d7
Add confirmation
Apr 16, 2020
7c99b10
remove text from help file
Apr 16, 2020
b0ac719
Update src/azure-cli/azure/cli/command_modules/iot/_help.py
Juliehzl Apr 17, 2020
7ed1bb5
Update src/azure-cli/azure/cli/command_modules/iot/commands.py
Juliehzl Apr 17, 2020
0696aa2
Update src/azure-cli/azure/cli/command_modules/iot/commands.py
Juliehzl Apr 17, 2020
4c9c6b2
fix style
Juliehzl Apr 17, 2020
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
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,9 @@ def get_pnp_client(repo_endpoint):
# pylint: disable=line-too-long
from .digitaltwinrepositoryprovisioningservice.digital_twin_repository_provisioning_service import DigitalTwinRepositoryProvisioningService
return DigitalTwinRepositoryProvisioningService(repo_endpoint)


def iot_central_service_factory(cli_ctx, *_):
from azure.cli.core.commands.client_factory import get_mgmt_service_client
from azure.mgmt.iotcentral import IotCentralClient
return get_mgmt_service_client(cli_ctx, IotCentralClient)
61 changes: 61 additions & 0 deletions src/azure-cli/azure/cli/command_modules/iot/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -908,3 +908,64 @@
text: >
az iot pnp repository update -r aaaabbbb11112222aaaabbbb1111222 -n updatedreponame
"""

helps['iot central'] = """
type: group
short-summary: Manage IoT Central assets.
"""

helps['iot central app'] = """
type: group
short-summary: Manage IoT Central applications.
"""

helps['iot central app create'] = """
type: command
short-summary: Create an IoT Central application.
long-summary: |
For an introduction to IoT Central, see https://docs.microsoft.com/azure/iot-central/.
The F1 Sku is no longer supported. Please use the ST2 Sku (default) for app creation.
For more pricing information, please visit https://azure.microsoft.com/pricing/details/iot-central/.
examples:
- name: Create an IoT Central application in the standard pricing tier ST2, in the region of the resource group.
text: >
az iot central app create --resource-group MyResourceGroup --name my-app-resource --subdomain my-app-subdomain
- name: Create an IoT Central application with the standard pricing tier ST2 in the 'westus' region, with a custom display name, based on the iotc-pnp-preview template.
text: >
az iot central app create --resource-group MyResourceGroup --name my-app-resource-name --sku ST2 --location westus --subdomain my-app-subdomain --template iotc-pnp-preview --display-name 'My Custom Display Name'
"""

helps['iot central app delete'] = """
type: command
short-summary: Delete an IoT Central application.
examples:
- name: Delete an IoT Central application. (autogenerated)
text: az iot central app delete --name MyIoTCentralApplication --resource-group MyResourceGroup
crafted: true
"""

helps['iot central app list'] = """
type: command
short-summary: List IoT Central applications.
examples:
- name: List all IoT Central applications in a subscription.
text: >
az iot central app list
- name: List all IoT Central applications in the resource group 'MyGroup'
text: >
az iot central app list --resource-group MyGroup
"""

helps['iot central app show'] = """
type: command
short-summary: Get the details of an IoT Central application.
examples:
- name: Show an IoT Central application.
text: >
az iot central app show --name MyApp
"""

helps['iot central app update'] = """
type: command
short-summary: Update metadata for an IoT Central application.
"""
21 changes: 21 additions & 0 deletions src/azure-cli/azure/cli/command_modules/iot/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
get_resource_name_completion_list,
get_enum_type,
get_three_state_flag)
from azure.mgmt.iotcentral.models import AppSku
from azure.mgmt.iothub.models import IotHubSku
from azure.mgmt.iothubprovisioningservices.models import (IotDpsSku,
AllocationPolicy,
Expand Down Expand Up @@ -42,6 +43,10 @@
completer=get_resource_name_completion_list('Microsoft.Devices/ProvisioningServices'),
help='IoT Provisioning Service name')

app_name_type = CLIArgumentType(
completer=get_resource_name_completion_list('Microsoft.IoTCentral/IoTApps'),
help='IoT Central application name.')


def load_arguments(self, _): # pylint: disable=too-many-statements
# Arguments for IoT DPS
Expand Down Expand Up @@ -274,3 +279,19 @@ def load_arguments(self, _): # pylint: disable=too-many-statements
help='Access key for the given IoT Plug and Play repository.')
c.argument('user_role', options_list=['--role'], arg_type=get_enum_type(UserRole),
help='User role of the access key for the given IoT Plug and Play repository.')

with self.argument_context('iot central app') as c:
c.argument('app_name', app_name_type, options_list=['--name', '-n'], id_part='display_name')

with self.argument_context('iot central app create') as c:
c.argument('app_name', completer=None)
c.argument('location', get_location_type(self.cli_ctx),
help='Location of your IoT Central application. Default is the location of target resource group.')
c.argument('sku', arg_type=get_enum_type(AppSku),
help='Pricing tier for IoT Central applications. Default value is ST2.')
c.argument('subdomain',
help='Subdomain for the IoT Central URL. Each application must have a unique subdomain.')
c.argument('template',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there allowed values for template?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, there is. We have an API that allows customers to see the available options.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not want to hardcode these values in the Azure CLI

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this way can we put the API in help message? Because for me (a new user), I totally don't know which value is available for template.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I can see how that can be confusing. We have an item in our backlog to rewrite the documentation for Swagger and Az CLI. I added some details about the issue of not seeing available templates so we can address it when we have the capacity.

help='IoT Central application template name. Default is a custom application.')
c.argument('display_name',
help='Custom display name for the IoT Central application. Default is resource name.')
13 changes: 13 additions & 0 deletions src/azure-cli/azure/cli/command_modules/iot/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from ._client_factory import iot_hub_service_factory
from ._client_factory import iot_service_provisioning_factory
from ._client_factory import iot_pnp_service_factory
from ._client_factory import iot_central_service_factory


JOB_DEPRECATION_INFO = 'IoT Extension (azure-cli-iot-ext) Job commands'
Expand Down Expand Up @@ -47,6 +48,10 @@ def load_command_table(self, _): # pylint: disable=too-many-statements

update_custom_util = CliCommandType(operations_tmpl='azure.cli.command_modules.iot.custom#{}')

iot_central_sdk = CliCommandType(
operations_tmpl='azure.mgmt.iotcentral.operations#IoTCentaralOperations.{}'
)

# iot dps commands
with self.command_group('iot dps', client_factory=iot_service_provisioning_factory) as g:
g.custom_command('list', 'iot_dps_list')
Expand Down Expand Up @@ -172,3 +177,11 @@ def load_command_table(self, _): # pylint: disable=too-many-statements
g.custom_command('create', 'pnp_create_key')
g.custom_command('delete', 'pnp_delete_key')
g.custom_command('update', 'pnp_update_key')

with self.command_group('iot central app', iot_central_sdk, client_factory=iot_central_service_factory) as g:
g.custom_command('create', 'iot_central_app_create')
g.custom_command('list', 'iot_central_app_list')
g.custom_show_command('show', 'iot_central_app_get')
g.generic_update_command('update', getter_name='iot_central_app_get',
setter_name='iot_central_app_update', command_type=update_custom_util)
g.custom_command('delete', 'iot_central_app_delete')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add confirmation=True for delete command.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reverted this change because this will break existing scripts customers are using. This will require them to pass in --yes in order for it proceeds with existing functionality we had before.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additionally, we really don't want to introduce any new functionality in this PR we just want to migrate existing command module code from iotcentral to iot

Copy link
Contributor

@Juliehzl Juliehzl Apr 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you add deprecation information for original commands? And because you already give users breaking change, and they need to change the scripts anyway, it should be fine to add one more -y in their scripts.

Please feel free to let me know your concern.

Copy link
Contributor Author

@r-delgadillo r-delgadillo Apr 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the deprecation information for az iotcentral command module is in ~/command_modules/iotcentral/commands.py in this PR. That makes sense about breaking them either way, I added it back thanks.

87 changes: 87 additions & 0 deletions src/azure-cli/azure/cli/command_modules/iot/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from __future__ import print_function
from enum import Enum
from knack.log import get_logger
from knack.util import CLIError
from azure.cli.core.commands import LongRunningOperation

Expand Down Expand Up @@ -38,6 +39,10 @@
IotDpsSku,
SharedAccessSignatureAuthorizationRuleAccessRightsDescription)


from azure.mgmt.iotcentral.models import (AppSkuInfo,
App)

from azure.cli.command_modules.iot.mgmt_iot_hub_device.lib.iot_hub_device_client import IotHubDeviceClient
from azure.cli.command_modules.iot.sas_token_auth import SasTokenAuthentication
from azure.cli.command_modules.iot.shared import EndpointType, EncodingFormat, RenewKeyType
Expand All @@ -46,6 +51,9 @@
from ._utils import open_certificate, get_auth_header, generateKey


logger = get_logger(__name__)


# CUSTOM TYPE
class KeyType(Enum):
primary = 'primary'
Expand Down Expand Up @@ -1093,3 +1101,82 @@ def _delete_routing_endpoints(endpoint_name, endpoint_type, endpoints):
endpoints.event_hubs = []

return endpoints


def iot_central_app_create(
cmd, client, app_name, resource_group_name, subdomain, sku="ST2",
location=None, template=None, display_name=None
):
cli_ctx = cmd.cli_ctx
location = _ensure_location(cli_ctx, resource_group_name, location)
display_name = _ensure_display_name(app_name, display_name)
appSku = AppSkuInfo(name=sku)

app = App(subdomain=subdomain,
location=location,
display_name=display_name,
sku=appSku,
template=template)

createResult = client.apps.create_or_update(
resource_group_name, app_name, app)
return createResult


def iot_central_app_get(client, app_name, resource_group_name=None):
if resource_group_name is None:
return _get_iot_central_app_by_name(client, app_name)
return client.apps.get(resource_group_name, app_name)


def iot_central_app_delete(client, app_name, resource_group_name):
return client.apps.delete(resource_group_name, app_name)


def iot_central_app_list(client, resource_group_name=None):
if resource_group_name is None:
return client.apps.list_by_subscription()
return client.apps.list_by_resource_group(resource_group_name)


def iot_central_app_update(client, app_name, parameters, resource_group_name):
etag = parameters.additional_properties['etag']
return client.apps.update(resource_group_name, app_name, parameters, {'IF-MATCH': etag})


def _ensure_location(cli_ctx, resource_group_name, location):
"""Check to see if a location was provided. If not,
fall back to the resource group location.
:param object cli_ctx: CLI Context
:param str resource_group_name: Resource group name
:param str location: Location to create the resource
"""
if location is None:
resource_group_client = resource_service_factory(
cli_ctx).resource_groups
return resource_group_client.get(resource_group_name).location
return location


def _ensure_display_name(app_name, display_name):
if not display_name or display_name.isspace():
return app_name
return display_name


def _get_iot_central_app_by_name(client, app_name):
"""Search the current subscription for an app with the given name.
:param object client: IoTCentralClient
:param str app_name: App name to search for
"""
all_apps = iot_central_app_list(client)
if all_apps is None:
raise CLIError(
"No IoT Central application found in current subscription.")
try:
target_app = next(
x for x in all_apps if app_name.lower() == x.name.lower())
except StopIteration:
raise CLIError(
"No IoT Central application found with name {} in current subscription.".format(app_name))
return target_app
Loading