Skip to content

Commit

Permalink
Onboard command extension for Azure Managed Grafana service (#4495)
Browse files Browse the repository at this point in the history
* POC: update with command list to implement

* consolidate control plane and dashboard commands

* half done: make resource group and location optional

* more commands and code style fixes

* add a validator to workspace https://bugs.python.org/issue9334

* catch up a few TODOs

* Consolidate data source CRUD commands with bug fixes and samples

* add help

* bug fixes on data source commands

* fix style errors

* fix bugs in data-source commands

* clean up command help

* upload whl file for tempoaray measures, before we publish it officially

* update readme and bug fixes

* update get_start doc

* Update get_start,md

* fix typos in get_start.md

* add vendor SDK

* new extension

* new extension built from azdev

* rename from ags to amg

* add tag support

* Update readme.rst

* undo non related changes

* rename readme to markdown

* address lint error

* address linter error

* more fix towards command lint error

* register the command module in a few common file

* add import

* support gallery import

* use deep copy

* address review feedback

* set the minimum cli core version

* fix a bug in 'az grafana user show'

* Remove the 'id' on creating dashboard to prevent 'Not Found' error
  • Loading branch information
yugangw-msft committed Mar 22, 2022
1 parent dde0bfc commit 0ad4600
Show file tree
Hide file tree
Showing 38 changed files with 5,088 additions and 2 deletions.
4 changes: 3 additions & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@

/src/datamigration/ @ashutoshsuman99

/src/amg/ @yugangw-msft

/src/confidentialledger/ @kairu-ms @lynshi

/src/quota/ @kairu-ms @ZengTaoxu
/src/quota/ @kairu-ms @ZengTaoxu
8 changes: 8 additions & 0 deletions src/amg/HISTORY.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.. :changelog:
Release History
===============

0.1.0
++++++
* Initial release.
55 changes: 55 additions & 0 deletions src/amg/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Microsoft Azure CLI 'amg' Extension
This is an extension to manage Azure Manaaged Grafana instances

## How to use ##
Install this extension using the below CLI command
```
az extension add --name amg
```

## Included Features
### Create, show, and delete instances

#### create an instance
*Examples:*
```
az grafana create \
-g MyResourceGroup \
-n MyGrafanaInstance \
--tags department=financial
```

#### delete an instance
*Examples:*
```
az grafana delete \
-n MyGrafanaInstance
```

### Configure folder, data sources and dashboard

#### create a folder
*Examples:*
```
az grafana folder create \
-n MyGrafanaInstance \
--title "Health KPI"
```

#### configure a data source
*Examples:*
```
az grafana data-source create \
-n MyGrafanaInstance \
--definition ~/data-source-sql.json
```

#### Create a dashboard
*Examples:*
```
az grafana dashboard create \
-n MyGrafanaInstance \
--folder "Health KPI" \
--title "SQL status" \
--definition ~/dashboard-sql.json
```
31 changes: 31 additions & 0 deletions src/amg/azext_amg/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from azure.cli.core import AzCommandsLoader

from azext_amg._help import helps # pylint: disable=unused-import


class AmgCommandsLoader(AzCommandsLoader):

def __init__(self, cli_ctx=None):
from azure.cli.core.commands import CliCommandType
amg_custom = CliCommandType(
operations_tmpl='azext_amg.custom#{}')
# pylint: disable=super-with-arguments
super(AmgCommandsLoader, self).__init__(cli_ctx=cli_ctx,
custom_command_type=amg_custom)

def load_command_table(self, args):
from azext_amg.commands import load_command_table
load_command_table(self, args)
return self.command_table

def load_arguments(self, command):
from azext_amg._params import load_arguments
load_arguments(self, command)


COMMAND_LOADER_CLS = AmgCommandsLoader
11 changes: 11 additions & 0 deletions src/amg/azext_amg/_client_factory.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.
# --------------------------------------------------------------------------------------------


def cf_amg(cli_ctx, *_):
# pylint: disable=unused-argument
from azure.cli.core.commands.client_factory import get_mgmt_service_client
from azext_amg.vendored_sdks import DashboardManagementClient
return get_mgmt_service_client(cli_ctx, DashboardManagementClient)
212 changes: 212 additions & 0 deletions src/amg/azext_amg/_help.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
# coding=utf-8
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from knack.help_files import helps # pylint: disable=unused-import


helps['grafana'] = """
type: group
short-summary: Commands to manage Azure Grafana instanced.
long-summary: For optimized experience, not all data plane Apis, documented at https://grafana.com/docs/grafana/latest/http_api/, are exposed. On coverage gap, please reach out to ad4g@microsoft.com
"""

helps['grafana create'] = """
type: command
short-summary: Create a Azure Managed Grafana instance.
"""

helps['grafana list'] = """
type: command
short-summary: List Azure Managed Grafana instances.
"""

helps['grafana delete'] = """
type: command
short-summary: Delete a Azure Managed Grafana instance.
"""

helps['grafana show'] = """
type: command
short-summary: Show details of a Azure Managed Grafana instance.
"""

helps['grafana data-source'] = """
type: group
short-summary: Commands to manage data sources of an instance.
"""

helps['grafana data-source create'] = """
type: command
short-summary: Create a data source.
examples:
- name: create a data source of Azure SQL
text: |
az grafana data-source create -n MyGrafana --definition '{
"access": "proxy",
"database": "testdb",
"jsonData": {
"authenticationType": "SQL Server Authentication",
"encrypt": "false"
},
"secureJsonData": {
"password": "verySecretPassword"
},
"name": "Microsoft SQL Server",
"type": "mssql",
"url": "testsql.database.windows.net",
"user": "admin1"
}'
"""


helps['grafana data-source update'] = """
type: command
short-summary: Update a data source.
"""

helps['grafana data-source show'] = """
type: command
short-summary: get details of a data source
"""

helps['grafana data-source delete'] = """
type: command
short-summary: delete a data source
"""

helps['grafana data-source list'] = """
type: command
short-summary: List all data sources of an instance.
"""

helps['grafana data-source query'] = """
type: command
short-summary: query a data source having backend implementation
"""

helps['grafana dashboard'] = """
type: group
short-summary: Commands to manage dashboards of an instance.
"""

helps['grafana dashboard create'] = """
type: command
short-summary: Create a new dashboard.
examples:
- name: Create a dashboard with definition in a json file. For quick start, clone from the output of "az grafana dashboard show", remove "id" and "uid", and apply changes.
text: |
az grafana dashboard create -g MyResourceGroup -n MyGrafana --title "My dashboard" --folder folder1 --definition '{
"dashboard": {
"annotations": {
...
},
"panels": {
...
}
},
"message": "Create a new test dashboard"
}'
"""

helps['grafana dashboard update'] = """
type: command
short-summary: Update a dashboard.
examples:
- name: Update a dashboard with definition in a json file. For quick start, get existing configuration from "az grafana dashboard show", and apply changes.
"version" field need to be updated, and "overwrite" field should be true.
text: |
az grafana dashboard update -g MyResourceGroup -n MyGrafana --definition @c:\\temp\\dashboard.json
"""

helps['grafana dashboard import'] = """
type: command
short-summary: import a dashboard.
long-summary: CLI command will fill in required parameters for data sources if configured
examples:
- name: import the dashboard of "AKS Container Insights" from Grafana gallery.
text: |
az grafana dashboard import -g MyResourceGroup -n MyGrafana --definition 12180
- name: import a dashboard from a file.
text: |
az grafana dashboard import -g MyResourceGroup -n MyGrafana --definition @c:\\temp\\dashboard.json
"""

helps['grafana dashboard list'] = """
type: command
short-summary: List all dashboards of an instance.
examples:
- name: Find the dashboard for K8s API Server and retrieve the unique identifier(in order to invoke "az grafana dashboard show" command)
text: |
az grafana dashboard list -g MyResourceGroup -n MyGrafana --query "[?contains(@.title, 'API server')].uid"
"""

helps['grafana dashboard show'] = """
type: command
short-summary: show the detail of a dashboard.
examples:
- name: Get details of a dashboard specified by an unique identifier(use "az grafana dashboard list" command to retrieve the uid)
text: |
az grafana dashboard show -g MyResourceGroup -n MyGrafana --dashboard VdrOA7jGz
"""

helps['grafana dashboard delete'] = """
type: command
short-summary: delete a dashboard
examples:
- name: Delete a dashboard specified by an unique identifier(use "az grafana dashboard list" command to retrieve the uid)
text: |
az grafana dashboard delete -g MyResourceGroup -n MyGrafana --dashboard VdrOA7jGz
"""

helps['grafana folder'] = """
type: group
short-summary: Commands to manage folders of an instance.
"""

helps['grafana folder create'] = """
type: command
short-summary: create a new folder.
"""

helps['grafana folder show'] = """
type: command
short-summary: show the details of a folder.
"""

helps['grafana folder list'] = """
type: command
short-summary: list all folders of an instance.
"""

helps['grafana folder update'] = """
type: command
short-summary: update a folder.
"""

helps['grafana folder delete'] = """
type: command
short-summary: delete a folder.
"""

helps['grafana user'] = """
type: group
short-summary: Commands to manage users of an instance.
"""

helps['grafana user actual-user'] = """
type: command
short-summary: show details of current user.
"""

helps['grafana user list'] = """
type: command
short-summary: list users.
"""

helps['grafana user show'] = """
type: command
short-summary: show detail of a user.
"""
57 changes: 57 additions & 0 deletions src/amg/azext_amg/_params.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# --------------------------------------------------------------------------------------------
# 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


def load_arguments(self, _):

from knack.arguments import CLIArgumentType
from azure.cli.core.commands.parameters import tags_type, get_three_state_flag
from azure.cli.core.commands.validators import get_default_location_from_resource_group
from ._validators import process_missing_resource_group_parameter

grafana_name_type = CLIArgumentType(options_list="--grafana-name",
help="Name of the Azure Managed Dashboard for Grafana.",
id_part="name")

with self.argument_context("grafana") as c:
c.argument("tags", tags_type)
c.argument("location", validator=get_default_location_from_resource_group)
c.argument("grafana_name", grafana_name_type, options_list=["--name", "-n"], id_part=None, validator=process_missing_resource_group_parameter)
c.argument("id", help=("The identifier (id) of a dashboard/data source is an auto-incrementing "
"numeric value and is only unique per Grafana install."))
c.argument("folder", help="id, uid, title which can identify a folder. CLI will search in the order of id, uid, and title, till finds a match")

with self.argument_context("grafana create") as c:
c.argument("grafana_name", grafana_name_type, options_list=["--name", "-n"], validator=None)
c.argument("skip_system_assigned_identity", options_list=["-s", "--skip-system-assigned-identity"], arg_type=get_three_state_flag(), help="Do not enable system assigned identity")
c.argument("skip_role_assignments", arg_type=get_three_state_flag(), help="Do not create role assignments for managed identity and the current login user")

with self.argument_context("grafana dashboard") as c:
c.argument("uid", options_list=["--dashboard"], help="dashboard uid")
c.argument("definition", help="The complete dashboard model in json string, a path or url to a file with such content")
c.argument("title", help="title of a dashboard")
c.argument('overwrite', arg_type=get_three_state_flag(), help='Overwrite a dashboard with same uid')

with self.argument_context("grafana dashboard import") as c:
c.argument("definition", help="The complete dashboard model in json string, Grafana gallery id, a path or url to a file with such content")

with self.argument_context("grafana data-source") as c:
c.argument("data_source", help="name, id, uid which can identify a data source. CLI will search in the order of name, id, and uid, till finds a match")
c.argument("definition", help="json string with data source definition, or a path to a file with such content")

with self.argument_context("grafana data-source query") as c:
c.argument("conditions", nargs="+", help="space-separated condition in a format of `<name>=<value>`")
c.argument("time_from", options_list=["--from"], help="start time in iso 8601, e.g. '2022-01-02T16:15:00'. Default: 1 hour early")
c.argument("time_to", options_list=["--to"], help="end time in iso 8601, e.g. '2022-01-02T17:15:00'. Default: current time ")
c.argument("max_data_points", help="Maximum amount of data points that dashboard panel can render")
c.argument("query_format", help="format of the resule, e.g. table, time_series")
c.argument("internal_ms", help="The time interval in milliseconds of time series")

with self.argument_context("grafana folder") as c:
c.argument("title", help="title of the folder")

with self.argument_context("grafana user") as c:
c.argument("user", help="user login name or email")
Loading

0 comments on commit 0ad4600

Please sign in to comment.