зеркало из https://github.com/Azure/ARO-RP.git
Implement ARO extension
Co-authored-by: Mangirdas Judeikis <Mangirdas@Judeikis.LT>
This commit is contained in:
Родитель
972eb709f3
Коммит
a3096fea90
|
@ -0,0 +1 @@
|
|||
PYTHONPATH=python/az/aro
|
|
@ -1,4 +1,4 @@
|
|||
name: pull_request-test
|
||||
name: pull_request-test-go
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
|
@ -21,5 +21,5 @@ jobs:
|
|||
- name: Test
|
||||
run: |
|
||||
set -x
|
||||
make test
|
||||
make test-go
|
||||
[[ -z "$(git status -s)" ]]
|
|
@ -0,0 +1,27 @@
|
|||
name: pull_request-test-python
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version:
|
||||
- 2.7
|
||||
- 3.5.7
|
||||
- 3.6.9
|
||||
steps:
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Check out source
|
||||
uses: actions/checkout@v1
|
||||
- name: Test
|
||||
run: |
|
||||
set -x
|
||||
pip install virtualenv
|
||||
make test-python
|
|
@ -1,9 +1,16 @@
|
|||
__pycache__
|
||||
*.egg-info
|
||||
*.pyc
|
||||
/.vscode
|
||||
/*.crt
|
||||
/*.key
|
||||
/*.pem
|
||||
/*.kubeconfig
|
||||
/*.pem
|
||||
/env*
|
||||
!/env.example
|
||||
/id_rsa
|
||||
/pyenv*
|
||||
/python/az/aro/build
|
||||
/python/az/aro/dist
|
||||
/rp
|
||||
/secrets
|
||||
|
|
22
Makefile
22
Makefile
|
@ -3,8 +3,13 @@ COMMIT = $(shell git rev-parse --short HEAD)$(shell [[ $$(git status --porcelain
|
|||
rp: generate
|
||||
go build -ldflags "-X main.gitCommit=$(COMMIT)" ./cmd/rp
|
||||
|
||||
az:
|
||||
cd python/az/aro && python ./setup.py bdist_egg
|
||||
|
||||
clean:
|
||||
rm -f rp
|
||||
rm -rf python/az/aro/{aro.egg-info,build,dist} rp
|
||||
find python -type f -name '*.pyc' -delete
|
||||
find python -type d -name __pycache__ -delete
|
||||
|
||||
client: generate
|
||||
rm -rf pkg/client python/client
|
||||
|
@ -33,6 +38,7 @@ client: generate
|
|||
|
||||
sudo chown -R $(USER):$(USER) pkg/client python/client
|
||||
rm -rf python/client/azure/mgmt/redhatopenshift/v2019_12_31_preview/aio
|
||||
>python/client/__init__.py
|
||||
|
||||
go run ./vendor/golang.org/x/tools/cmd/goimports -w -local=github.com/jim-minter/rp pkg/client
|
||||
|
||||
|
@ -50,7 +56,7 @@ secrets:
|
|||
secrets-update:
|
||||
oc create secret generic aro-v4-dev --from-file=secrets --dry-run -o yaml | oc apply -f -
|
||||
|
||||
test: generate
|
||||
test-go: generate
|
||||
go build ./...
|
||||
|
||||
gofmt -s -w cmd hack pkg
|
||||
|
@ -63,4 +69,14 @@ test: generate
|
|||
go vet ./...
|
||||
go test ./...
|
||||
|
||||
.PHONY: rp clean client generate image secrets secrets-update test
|
||||
test-python:
|
||||
virtualenv --python=/usr/bin/python${PYTHON_VERSION} pyenv${PYTHON_VERSION}
|
||||
. pyenv${PYTHON_VERSION}/bin/activate && \
|
||||
pip install azdev && \
|
||||
azdev setup -r . && \
|
||||
sed -i -e "s|^dev_sources = $(PWD)$$|dev_sources = $(PWD)/python|" ~/.azure/config && \
|
||||
$(MAKE) az && \
|
||||
azdev linter && \
|
||||
azdev style
|
||||
|
||||
.PHONY: rp az clean client generate image secrets secrets-update test-go test-python
|
||||
|
|
42
README.md
42
README.md
|
@ -13,6 +13,17 @@
|
|||
az login
|
||||
```
|
||||
|
||||
1. Add the ARO preview extension to `az`:
|
||||
|
||||
```
|
||||
make az
|
||||
|
||||
cat >>~/.azure/config <<EOF
|
||||
[extension]
|
||||
dev_sources = $(go env GOPATH)/src/github.com/jim-minter/rp/python
|
||||
EOF
|
||||
```
|
||||
|
||||
1. You will need a publicly resolvable **DNS zone** resource in your Azure
|
||||
subscription. *RH ARO engineering*: use the `osadev.cloud` zone in the `dns`
|
||||
resource group.
|
||||
|
@ -62,15 +73,6 @@
|
|||
*RH ARO engineering*: use the `localhost` key and certificate in the shared
|
||||
`secrets/localhost.pem` file.
|
||||
|
||||
1. You will need your own **cluster AAD application** with client secret
|
||||
authentication enabled.
|
||||
|
||||
```
|
||||
AZURE_CLUSTER_CLIENT_ID="$(az ad app create --display-name "user-$USER-v4" --query appId -o tsv)"
|
||||
az ad sp create --id "$AZURE_CLUSTER_CLIENT_ID"
|
||||
AZURE_CLUSTER_CLIENT_SECRET="$(az ad app credential reset --id "$AZURE_CLUSTER_CLIENT_ID" --query password -o tsv)"
|
||||
```
|
||||
|
||||
1. Copy env.example to env, edit the values and source the env file. This file
|
||||
holds (only) the environment variables necessary for the RP to run.
|
||||
|
||||
|
@ -85,8 +87,6 @@
|
|||
* AZURE_FP_CLIENT_ID: RP "first party" application client UUID
|
||||
* AZURE_CLIENT_ID: RP AAD application client UUID
|
||||
* AZURE_CLIENT_SECRET: RP AAD application client secret
|
||||
* AZURE_CLUSTER_CLIENT_ID: Cluster AAD application client UUID
|
||||
* AZURE_CLUSTER_CLIENT_SECRET: Cluster AAD application client secret
|
||||
|
||||
* PULL_SECRET: A cluster pull secret retrieved from [Red Hat OpenShift Cluster Manager](https://cloud.redhat.com/openshift/install/azure/installer-provisioned)
|
||||
|
||||
|
@ -156,13 +156,11 @@ go run ./cmd/rp
|
|||
## Useful commands
|
||||
|
||||
```
|
||||
export VNET_RESOURCEGROUP="$RESOURCEGROUP-vnet"
|
||||
VNET_RESOURCEGROUP="$RESOURCEGROUP-vnet"
|
||||
az group create -g "$VNET_RESOURCEGROUP" -l "$LOCATION"
|
||||
az network vnet create -g "$VNET_RESOURCEGROUP" -n vnet --address-prefixes 10.0.0.0/9
|
||||
az role assignment create --role "ARO v4 Development Subnet Contributor" --assignee-object-id "$(az ad sp list --all --query "[?appId=='$AZURE_FP_CLIENT_ID'].objectId" -o tsv)" --scope "/subscriptions/$AZURE_SUBSCRIPTION_ID/resourceGroups/$VNET_RESOURCEGROUP/providers/Microsoft.Network/virtualNetworks/vnet"
|
||||
az role assignment create --role "ARO v4 Development Subnet Contributor" --assignee-object-id "$(az ad sp list --all --query "[?appId=='$AZURE_CLUSTER_CLIENT_ID'].objectId" -o tsv)" --scope "/subscriptions/$AZURE_SUBSCRIPTION_ID/resourceGroups/$VNET_RESOURCEGROUP/providers/Microsoft.Network/virtualNetworks/vnet"
|
||||
|
||||
export CLUSTER=cluster
|
||||
CLUSTER=cluster
|
||||
```
|
||||
|
||||
* Register a subscription:
|
||||
|
@ -177,31 +175,31 @@ curl -k -X PUT "https://localhost:8443/subscriptions/$AZURE_SUBSCRIPTION_ID?api-
|
|||
az network vnet subnet create -g "$VNET_RESOURCEGROUP" --vnet-name vnet -n "$CLUSTER-master" --address-prefixes "10.$((RANDOM & 127)).$((RANDOM & 255)).0/24"
|
||||
az network vnet subnet create -g "$VNET_RESOURCEGROUP" --vnet-name vnet -n "$CLUSTER-worker" --address-prefixes "10.$((RANDOM & 127)).$((RANDOM & 255)).0/24"
|
||||
|
||||
envsubst <examples/cluster-v20191231.json | curl -k -X PUT "https://localhost:8443/subscriptions/$AZURE_SUBSCRIPTION_ID/resourceGroups/$RESOURCEGROUP/providers/Microsoft.RedHatOpenShift/openShiftClusters/$CLUSTER?api-version=2019-12-31-preview" -H 'Content-Type: application/json' -d @-
|
||||
az aro create -g "$RESOURCEGROUP" -n "$CLUSTER" --vnet-resource-group "$VNET_RESOURCEGROUP" --vnet vnet --master-subnet "$CLUSTER-master" --worker-subnet "$CLUSTER-worker" --location="$LOCATION"
|
||||
```
|
||||
|
||||
* Get a cluster:
|
||||
|
||||
```
|
||||
curl -k "https://localhost:8443/subscriptions/$AZURE_SUBSCRIPTION_ID/resourceGroups/$RESOURCEGROUP/providers/Microsoft.RedHatOpenShift/openShiftClusters/$CLUSTER?api-version=2019-12-31-preview"
|
||||
az aro show -g "$RESOURCEGROUP" -n "$CLUSTER"
|
||||
```
|
||||
|
||||
* Get a cluster's kubeadmin credentials:
|
||||
|
||||
```
|
||||
curl -k -X POST "https://localhost:8443/subscriptions/$AZURE_SUBSCRIPTION_ID/resourceGroups/$RESOURCEGROUP/providers/Microsoft.RedHatOpenShift/openShiftClusters/$CLUSTER/credentials?api-version=2019-12-31-preview" -H 'Content-Type: application/json' -d '{}'
|
||||
az aro get-credentials -g "$RESOURCEGROUP" -n "$CLUSTER"
|
||||
```
|
||||
|
||||
* List clusters in resource group:
|
||||
|
||||
```
|
||||
curl -k "https://localhost:8443/subscriptions/$AZURE_SUBSCRIPTION_ID/resourceGroups/$RESOURCEGROUP/providers/Microsoft.RedHatOpenShift/openShiftClusters?api-version=2019-12-31-preview"
|
||||
az aro list -g "$RESOURCEGROUP"
|
||||
```
|
||||
|
||||
* List clusters in subscription:
|
||||
|
||||
```
|
||||
curl -k "https://localhost:8443/subscriptions/$AZURE_SUBSCRIPTION_ID/providers/Microsoft.RedHatOpenShift/openShiftClusters?api-version=2019-12-31-preview"
|
||||
az aro list
|
||||
```
|
||||
|
||||
* Scale a cluster:
|
||||
|
@ -209,13 +207,13 @@ curl -k "https://localhost:8443/subscriptions/$AZURE_SUBSCRIPTION_ID/providers/M
|
|||
```
|
||||
COUNT=4
|
||||
|
||||
curl -k -X PATCH "https://localhost:8443/subscriptions/$AZURE_SUBSCRIPTION_ID/resourceGroups/$RESOURCEGROUP/providers/Microsoft.RedHatOpenShift/openShiftClusters/$CLUSTER?api-version=2019-12-31-preview" -H 'Content-Type: application/json' -d '{"properties": {"workerProfiles": [{"name": "worker", "count": '"$COUNT"'}]}}'
|
||||
az aro update -g "$RESOURCEGROUP" -n "$CLUSTER" --worker-count "$COUNT"
|
||||
```
|
||||
|
||||
* Delete a cluster:
|
||||
|
||||
```
|
||||
curl -k -X DELETE "https://localhost:8443/subscriptions/$AZURE_SUBSCRIPTION_ID/resourceGroups/$RESOURCEGROUP/providers/Microsoft.RedHatOpenShift/openShiftClusters/$CLUSTER?api-version=2019-12-31-preview"
|
||||
az aro delete -g "$RESOURCEGROUP" -n "$CLUSTER"
|
||||
|
||||
az network vnet subnet delete -g "$VNET_RESOURCEGROUP" --vnet-name vnet -n "$CLUSTER-master"
|
||||
az network vnet subnet delete -g "$VNET_RESOURCEGROUP" --vnet-name vnet -n "$CLUSTER-worker"
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
# Deploy production cluster
|
||||
|
||||
export VNET_RESOURCEGROUP=$RESOURCEGROUP-vnet
|
||||
|
||||
export CLUSTER=cluster
|
||||
VNET_RESOURCEGROUP=$RESOURCEGROUP-vnet
|
||||
CLUSTER=cluster
|
||||
|
||||
az group create -g "$VNET_RESOURCEGROUP" -l "$LOCATION"
|
||||
az network vnet create -g "$VNET_RESOURCEGROUP" -n vnet --address-prefixes 10.0.0.0/9
|
||||
az network vnet subnet create -g "$VNET_RESOURCEGROUP" --vnet-name vnet -n "$CLUSTER-master" --address-prefixes 10.$((RANDOM & 127)).$((RANDOM & 255)).0/24
|
||||
az network vnet subnet create -g "$VNET_RESOURCEGROUP" --vnet-name vnet -n "$CLUSTER-worker" --address-prefixes 10.$((RANDOM & 127)).$((RANDOM & 255)).0/24
|
||||
|
||||
az role assignment create --role "ARO v4 Development Subnet Contributor" --assignee-object-id "$(az ad sp list --all --query "[?appId=='f1dd0a37-89c6-4e07-bcd1-ffd3d43d8875'].objectId" -o tsv)" --scope "/subscriptions/$AZURE_SUBSCRIPTION_ID/resourceGroups/$VNET_RESOURCEGROUP/providers/Microsoft.Network/virtualNetworks/vnet"
|
||||
|
||||
az aro create --resource-group $RESOURCEGROUP --name $CLUSTER --client-id $AZURE_CLUSTER_CLIENT_ID --client-secret $AZURE_CLUSTER_CLIENT_SECRET --vnet-rg-name $VNET_RESOURCEGROUP
|
||||
az aro create -g "$RESOURCEGROUP" -n "$CLUSTER" --vnet-resource-group "$VNET_RESOURCEGROUP" --vnet vnet --master-subnet "$CLUSTER-master" --worker-subnet "$CLUSTER-worker"
|
||||
|
|
|
@ -4,8 +4,6 @@ export RP_MODE=development
|
|||
|
||||
# RH ARO engineering: uncomment the following stanza only and run `make secrets`
|
||||
#. secrets/env
|
||||
#export AZURE_CLUSTER_CLIENT_ID=<xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx>
|
||||
#export AZURE_CLUSTER_CLIENT_SECRET=<secret>
|
||||
|
||||
# non-RH ARO engineering: uncomment from here
|
||||
#export AZURE_TENANT_ID=<xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx>
|
||||
|
@ -15,6 +13,4 @@ export RP_MODE=development
|
|||
#export AZURE_FP_CLIENT_ID=<xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx>
|
||||
#export AZURE_CLIENT_ID=<xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx>
|
||||
#export AZURE_CLIENT_SECRET=<secret>
|
||||
#export AZURE_CLUSTER_CLIENT_ID=<xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx>
|
||||
#export AZURE_CLUSTER_CLIENT_SECRET=<secret>
|
||||
#export PULL_SECRET='<secret-json-object>'
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
{
|
||||
"id": "/subscriptions/$AZURE_SUBSCRIPTION_ID/resourcegroups/$RESOURCEGROUP/providers/Microsoft.RedHatOpenShift/openShiftClusters/$CLUSTER",
|
||||
"name": "$CLUSTER",
|
||||
"type": "Microsoft.RedHatOpenShift/openShiftClusters",
|
||||
"location": "$LOCATION",
|
||||
"properties": {
|
||||
"servicePrincipalProfile": {
|
||||
"clientId": "$AZURE_CLUSTER_CLIENT_ID",
|
||||
"clientSecret": "$AZURE_CLUSTER_CLIENT_SECRET"
|
||||
},
|
||||
"networkProfile": {
|
||||
"podCidr": "10.128.0.0/14",
|
||||
"serviceCidr": "172.30.0.0/16"
|
||||
},
|
||||
"masterProfile": {
|
||||
"vmSize": "Standard_D8s_v3",
|
||||
"subnetId": "/subscriptions/$AZURE_SUBSCRIPTION_ID/resourcegroups/$VNET_RESOURCEGROUP/providers/Microsoft.Network/virtualNetworks/vnet/subnets/$CLUSTER-master"
|
||||
},
|
||||
"workerProfiles": [
|
||||
{
|
||||
"name": "worker",
|
||||
"vmSize": "Standard_D2s_v3",
|
||||
"diskSizeGB": 128,
|
||||
"subnetId": "/subscriptions/$AZURE_SUBSCRIPTION_ID/resourcegroups/$VNET_RESOURCEGROUP/providers/Microsoft.Network/virtualNetworks/vnet/subnets/$CLUSTER-worker",
|
||||
"count": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,26 +1,22 @@
|
|||
from azext_aro._client_factory import cf_aro
|
||||
from azext_aro._params import load_arguments
|
||||
from azext_aro.commands import load_command_table
|
||||
from azure.cli.core import AzCommandsLoader
|
||||
|
||||
from azext_aro._help import helps # pylint: disable=unused-import
|
||||
from azure.cli.core.commands import CliCommandType
|
||||
|
||||
|
||||
class AroCommandsLoader(AzCommandsLoader):
|
||||
|
||||
def __init__(self, cli_ctx=None):
|
||||
from azure.cli.core.commands import CliCommandType
|
||||
from azext_aro._client_factory import cf_aro
|
||||
aro_custom = CliCommandType(
|
||||
operations_tmpl='azext_aro.custom#{}',
|
||||
aro_custom = CliCommandType(operations_tmpl='azext_aro.custom#{}',
|
||||
client_factory=cf_aro)
|
||||
super(AroCommandsLoader, self).__init__(cli_ctx=cli_ctx,
|
||||
custom_command_type=aro_custom)
|
||||
|
||||
def load_command_table(self, args):
|
||||
from azext_aro.commands import load_command_table
|
||||
load_command_table(self, args)
|
||||
return self.command_table
|
||||
|
||||
def load_arguments(self, command):
|
||||
from azext_aro._params import load_arguments
|
||||
load_arguments(self, command)
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
import datetime
|
||||
import uuid
|
||||
|
||||
from azure.cli.core._profile import Profile
|
||||
from azure.cli.core.commands.client_factory import configure_common_settings
|
||||
from azure.graphrbac import GraphRbacManagementClient
|
||||
from azure.graphrbac.models import ApplicationCreateParameters
|
||||
from azure.graphrbac.models import PasswordCredential
|
||||
from azure.graphrbac.models import ServicePrincipalCreateParameters
|
||||
|
||||
|
||||
class AADManager(object):
|
||||
MANAGED_APP_PREFIX = "https://az.aro.azure.com/"
|
||||
|
||||
def __init__(self, cli_ctx):
|
||||
profile = Profile(cli_ctx=cli_ctx)
|
||||
credentials, _, tenant_id = profile.get_login_credentials(
|
||||
resource=cli_ctx.cloud.endpoints.active_directory_graph_resource_id)
|
||||
self.client = GraphRbacManagementClient(
|
||||
credentials, tenant_id, base_url=cli_ctx.cloud.endpoints.active_directory_graph_resource_id)
|
||||
configure_common_settings(cli_ctx, self.client)
|
||||
|
||||
def createManagedApplication(self, display_name):
|
||||
password = uuid.uuid4()
|
||||
|
||||
try:
|
||||
end_date = datetime.datetime(2299, 12, 31, tzinfo=datetime.timezone.utc)
|
||||
except AttributeError:
|
||||
end_date = datetime.datetime(2299, 12, 31)
|
||||
|
||||
app = self.client.applications.create(ApplicationCreateParameters(
|
||||
display_name=display_name,
|
||||
identifier_uris=[
|
||||
self.MANAGED_APP_PREFIX + str(uuid.uuid4()),
|
||||
],
|
||||
password_credentials=[
|
||||
PasswordCredential(
|
||||
end_date=end_date,
|
||||
value=password,
|
||||
),
|
||||
],
|
||||
))
|
||||
|
||||
return app, password
|
||||
|
||||
def getApplication(self, app_id):
|
||||
apps = list(self.client.applications.list(
|
||||
filter="appId eq '%s'" % app_id))
|
||||
if apps:
|
||||
return apps[0]
|
||||
return None
|
||||
|
||||
def deleteManagedApplication(self, app_id):
|
||||
app = self.getApplication(app_id)
|
||||
if app and app.identifier_uris and app.identifier_uris[0].startswith(self.MANAGED_APP_PREFIX):
|
||||
self.client.applications.delete(app.object_id)
|
||||
|
||||
def getServicePrincipal(self, app_id):
|
||||
sps = list(self.client.service_principals.list(
|
||||
filter="appId eq '%s'" % app_id))
|
||||
if sps:
|
||||
return sps[0]
|
||||
return None
|
||||
|
||||
def createServicePrincipal(self, app_id):
|
||||
return self.client.service_principals.create(ServicePrincipalCreateParameters(
|
||||
app_id=app_id,
|
||||
))
|
|
@ -1,7 +1,17 @@
|
|||
def cf_aro(cli_ctx, *_):
|
||||
import urllib3
|
||||
|
||||
from azure.cli.core.commands.client_factory import get_mgmt_service_client
|
||||
# TODO: Replace CONTOSO with the appropriate label and uncomment
|
||||
# from azure.mgmt.CONTOSO import CONTOSOManagementClient
|
||||
# return get_mgmt_service_client(cli_ctx, CONTOSOManagementClient)
|
||||
return None
|
||||
from azext_aro.custom import rp_mode_development
|
||||
from azext_aro.vendored_sdks.azure.mgmt.redhatopenshift.v2019_12_31_preview import AzureRedHatOpenShiftClient
|
||||
from azure.cli.core.commands.client_factory import get_mgmt_service_client
|
||||
|
||||
|
||||
def cf_aro(cli_ctx, *_):
|
||||
client = get_mgmt_service_client(
|
||||
cli_ctx, AzureRedHatOpenShiftClient).open_shift_clusters
|
||||
|
||||
if rp_mode_development():
|
||||
client.config.base_url = "https://localhost:8443/"
|
||||
client.config.connection.verify = False
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
return client
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import collections
|
||||
|
||||
from msrestazure.tools import parse_resource_id
|
||||
|
||||
|
||||
def aro_list_table_format(results):
|
||||
return [aro_show_table_format(r) for r in results]
|
||||
|
||||
|
||||
def aro_show_table_format(result):
|
||||
parts = parse_resource_id(result["id"])
|
||||
|
||||
return collections.OrderedDict(
|
||||
Name=result["name"],
|
||||
ResourceGroup=parts["resource_group"],
|
||||
Location=result["location"],
|
||||
ProvisioningState=result["provisioningState"],
|
||||
WorkerCount=result["workerProfiles"][0]["count"],
|
||||
ConsoleURL=result["consoleUrl"],
|
||||
)
|
|
@ -1,34 +1,37 @@
|
|||
# coding=utf-8
|
||||
|
||||
from knack.help_files import helps # pylint: disable=unused-import
|
||||
from knack.help_files import helps
|
||||
|
||||
|
||||
helps['aro'] = """
|
||||
type: group
|
||||
short-summary: Commands to manage Aros.
|
||||
short-summary: Manage Azure Red Hat OpenShift clusters.
|
||||
"""
|
||||
|
||||
helps['aro create'] = """
|
||||
type: command
|
||||
short-summary: Create a Aro.
|
||||
short-summary: Create a cluster.
|
||||
"""
|
||||
|
||||
helps['aro list'] = """
|
||||
type: command
|
||||
short-summary: List Aros.
|
||||
short-summary: List clusters.
|
||||
"""
|
||||
|
||||
# helps['aro delete'] = """
|
||||
# type: command
|
||||
# short-summary: Delete a Aro.
|
||||
# """
|
||||
helps['aro delete'] = """
|
||||
type: command
|
||||
short-summary: Delete a cluster.
|
||||
"""
|
||||
|
||||
# helps['aro show'] = """
|
||||
# type: command
|
||||
# short-summary: Show details of a Aro.
|
||||
# """
|
||||
helps['aro show'] = """
|
||||
type: command
|
||||
short-summary: Get the details of a cluster.
|
||||
"""
|
||||
|
||||
# helps['aro update'] = """
|
||||
# type: command
|
||||
# short-summary: Update a Aro.
|
||||
# """
|
||||
helps['aro update'] = """
|
||||
type: command
|
||||
short-summary: Update a cluster.
|
||||
"""
|
||||
|
||||
helps['aro get-credentials'] = """
|
||||
type: command
|
||||
short-summary: Get credentials of a cluster.
|
||||
"""
|
||||
|
|
|
@ -1,19 +1,62 @@
|
|||
# pylint: disable=line-too-long
|
||||
|
||||
from knack.arguments import CLIArgumentType
|
||||
from azext_aro._validators import validate_cidr
|
||||
from azext_aro._validators import validate_client_id
|
||||
from azext_aro._validators import validate_client_secret
|
||||
from azext_aro._validators import validate_subnet
|
||||
from azext_aro._validators import validate_vnet
|
||||
from azext_aro._validators import validate_worker_count
|
||||
from azext_aro._validators import validate_worker_vm_disk_size_gb
|
||||
from azure.cli.core.commands.parameters import name_type
|
||||
from azure.cli.core.commands.parameters import resource_group_name_type
|
||||
from azure.cli.core.commands.parameters import tags_type
|
||||
from azure.cli.core.commands.validators import get_default_location_from_resource_group
|
||||
|
||||
|
||||
def load_arguments(self, _):
|
||||
|
||||
from azure.cli.core.commands.parameters import tags_type
|
||||
from azure.cli.core.commands.validators import get_default_location_from_resource_group
|
||||
|
||||
aro_name_type = CLIArgumentType(options_list='--aro-name-name', help='Name of the Aro.', id_part='name')
|
||||
|
||||
with self.argument_context('aro') as c:
|
||||
c.argument('tags', tags_type)
|
||||
c.argument('location', validator=get_default_location_from_resource_group)
|
||||
c.argument('aro_name', aro_name_type, options_list=['--name', '-n'])
|
||||
c.argument('location',
|
||||
validator=get_default_location_from_resource_group)
|
||||
c.argument('resource_name',
|
||||
name_type,
|
||||
help='Name of cluster.')
|
||||
c.argument('tags',
|
||||
tags_type)
|
||||
|
||||
with self.argument_context('aro list') as c:
|
||||
c.argument('aro_name', aro_name_type, id_part=None)
|
||||
c.argument('client_id',
|
||||
help='Client ID of cluster service principal.',
|
||||
validator=validate_client_id)
|
||||
c.argument('client_secret',
|
||||
help='Client secret of cluster service principal.',
|
||||
validator=validate_client_secret)
|
||||
|
||||
c.argument('pod_cidr',
|
||||
help='CIDR of pod network.',
|
||||
validator=validate_cidr('pod_cidr'))
|
||||
c.argument('service_cidr',
|
||||
help='CIDR of service network.',
|
||||
validator=validate_cidr('service_cidr'))
|
||||
|
||||
c.argument('master_vm_size',
|
||||
help='Size of master VMs.')
|
||||
|
||||
c.argument('worker_vm_size',
|
||||
help='Size of worker VMs.')
|
||||
c.argument('worker_vm_disk_size_gb',
|
||||
help='Disk size in GB of worker VMs.',
|
||||
validator=validate_worker_vm_disk_size_gb)
|
||||
c.argument('worker_count',
|
||||
help='Count of worker VMs.',
|
||||
validator=validate_worker_count)
|
||||
|
||||
c.argument('vnet_resource_group_name',
|
||||
resource_group_name_type,
|
||||
options_list=['--vnet-resource-group'],
|
||||
help='Name of vnet resource group.')
|
||||
c.argument('vnet',
|
||||
help='Name or ID of vnet. If name is supplied, `--vnet-resource-group` must be supplied.',
|
||||
validator=validate_vnet)
|
||||
c.argument('master_subnet',
|
||||
help='Name or ID of master vnet subnet. If name is supplied, `--vnet` must be supplied.',
|
||||
validator=validate_subnet('master_subnet'))
|
||||
c.argument('worker_subnet',
|
||||
help='Name or ID of worker vnet subnet. If name is supplied, `--vnet` must be supplied.',
|
||||
validator=validate_subnet('worker_subnet'))
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
import uuid
|
||||
|
||||
from azure.cli.core.commands.client_factory import get_mgmt_service_client
|
||||
from azure.cli.core.commands.client_factory import get_subscription_id
|
||||
from azure.cli.core.profiles import get_sdk
|
||||
from azure.cli.core.profiles import ResourceType
|
||||
from msrestazure.azure_exceptions import CloudError
|
||||
from msrestazure.tools import resource_id
|
||||
|
||||
|
||||
CONTRIBUTOR = "b24988ac-6180-42a0-ab88-20f7382dd24c"
|
||||
|
||||
|
||||
def assign_contributor_to_vnet(cli_ctx, vnet, object_id):
|
||||
client = get_mgmt_service_client(cli_ctx, ResourceType.MGMT_AUTHORIZATION)
|
||||
|
||||
RoleAssignmentCreateParameters = get_sdk(cli_ctx, ResourceType.MGMT_AUTHORIZATION,
|
||||
'RoleAssignmentCreateParameters', mod='models',
|
||||
operation_group='role_assignments')
|
||||
|
||||
try:
|
||||
client.role_assignments.create(vnet, uuid.uuid4(), RoleAssignmentCreateParameters(
|
||||
role_definition_id=resource_id(
|
||||
subscription=get_subscription_id(cli_ctx),
|
||||
namespace='Microsoft.Authorization',
|
||||
type='roleDefinitions',
|
||||
name=CONTRIBUTOR,
|
||||
),
|
||||
principal_id=object_id,
|
||||
principal_type="ServicePrincipal",
|
||||
))
|
||||
except CloudError as err:
|
||||
if err.status_code == 409:
|
||||
return
|
||||
raise err
|
|
@ -1,14 +1,162 @@
|
|||
def example_name_or_id_validator(cmd, namespace):
|
||||
# Example of a storage account name or ID validator.
|
||||
# See: https://github.com/Azure/azure-cli/blob/dev/doc/authoring_command_modules/authoring_commands.md#supporting-name-or-id-parameters
|
||||
from azure.cli.core.commands.client_factory import get_subscription_id
|
||||
from msrestazure.tools import is_valid_resource_id, resource_id
|
||||
if namespace.storage_account:
|
||||
if not is_valid_resource_id(namespace.RESOURCE):
|
||||
namespace.storage_account = resource_id(
|
||||
subscription=get_subscription_id(cmd.cli_ctx),
|
||||
resource_group=namespace.resource_group_name,
|
||||
namespace='Microsoft.Storage',
|
||||
type='storageAccounts',
|
||||
name=namespace.storage_account
|
||||
import ipaddress
|
||||
import uuid
|
||||
|
||||
from azure.cli.core.commands.client_factory import get_mgmt_service_client
|
||||
from azure.cli.core.commands.client_factory import get_subscription_id
|
||||
from azure.cli.core.profiles import ResourceType
|
||||
from knack.util import CLIError
|
||||
from msrestazure.azure_exceptions import CloudError
|
||||
from msrestazure.tools import is_valid_resource_id
|
||||
from msrestazure.tools import parse_resource_id
|
||||
from msrestazure.tools import resource_id
|
||||
|
||||
|
||||
def validate_cidr(key):
|
||||
def _validate_cidr(namespace):
|
||||
cidr = getattr(namespace, key)
|
||||
if cidr is not None:
|
||||
try:
|
||||
ipaddress.IPv4Network(cidr)
|
||||
except ValueError:
|
||||
raise CLIError("Invalid --%s '%s'." %
|
||||
(key.replace('_', '-'), cidr))
|
||||
|
||||
return _validate_cidr
|
||||
|
||||
|
||||
def validate_client_id(namespace):
|
||||
if namespace.client_id is not None:
|
||||
try:
|
||||
uuid.UUID(namespace.client_id)
|
||||
except ValueError:
|
||||
raise CLIError("Invalid --client-id '%s'." % namespace.client_id)
|
||||
|
||||
if namespace.client_secret is None or not str(namespace.client_secret):
|
||||
raise CLIError("Must specify --client-secret with --client-id.")
|
||||
|
||||
|
||||
def validate_client_secret(namespace):
|
||||
if namespace.client_secret is not None:
|
||||
if namespace.client_id is not None or not str(namespace.client_id):
|
||||
raise CLIError("Must specify --client-id with --client-secret.")
|
||||
|
||||
|
||||
def _validate_int(key, i):
|
||||
try:
|
||||
i = int(i)
|
||||
except ValueError:
|
||||
raise CLIError("Invalid --%s '%s'." % (key.replace('_', '-'), i))
|
||||
|
||||
return i
|
||||
|
||||
|
||||
def validate_subnet(key):
|
||||
def _validate_subnet(cmd, namespace):
|
||||
subnet = getattr(namespace, key)
|
||||
|
||||
if not is_valid_resource_id(subnet):
|
||||
if not namespace.vnet:
|
||||
raise CLIError(
|
||||
"Must specify --vnet if --%s is not an id." % key.replace('_', '-'))
|
||||
|
||||
validate_vnet(cmd, namespace)
|
||||
|
||||
subnet = namespace.vnet + "/subnets/" + subnet
|
||||
setattr(namespace, key, subnet)
|
||||
|
||||
parts = parse_resource_id(subnet)
|
||||
|
||||
if parts["subscription"] != get_subscription_id(cmd.cli_ctx):
|
||||
raise CLIError("--%s subscription '%s' must equal cluster subscription." %
|
||||
(key.replace('_', '-'), parts["subscription"]))
|
||||
|
||||
if parts["namespace"].lower() != "microsoft.network":
|
||||
raise CLIError("--%s namespace '%s' must equal Microsoft.Network." %
|
||||
(key.replace('_', '-'), parts["namespace"]))
|
||||
|
||||
if parts["type"].lower() != "virtualnetworks":
|
||||
raise CLIError("--%s type '%s' must equal virtualNetworks." %
|
||||
(key.replace('_', '-'), parts["type"]))
|
||||
|
||||
if parts["last_child_num"] != 1:
|
||||
raise CLIError("--%s '%s' must have one child." %
|
||||
(key.replace('_', '-'), subnet))
|
||||
|
||||
if "child_namespace_1" in parts:
|
||||
raise CLIError("--%s '%s' must not have child namespace." %
|
||||
(key.replace('_', '-'), subnet))
|
||||
|
||||
if parts["child_type_1"].lower() != "subnets":
|
||||
raise CLIError("--%s child type '%s' must equal subnets." %
|
||||
(key.replace('_', '-'), subnet))
|
||||
|
||||
client = get_mgmt_service_client(
|
||||
cmd.cli_ctx, ResourceType.MGMT_NETWORK)
|
||||
try:
|
||||
client.subnets.get(parts["resource_group"],
|
||||
parts["name"], parts["child_name_1"])
|
||||
except CloudError as err:
|
||||
raise CLIError(err.message)
|
||||
|
||||
return _validate_subnet
|
||||
|
||||
|
||||
def validate_subnets(master_subnet, worker_subnet):
|
||||
master_parts = parse_resource_id(master_subnet)
|
||||
worker_parts = parse_resource_id(worker_subnet)
|
||||
|
||||
if master_parts["resource_group"].lower() != worker_parts["resource_group"].lower():
|
||||
raise CLIError("--master-subnet resource group '%s' must equal --worker-subnet resource group '%s'." %
|
||||
(master_parts["resource_group"], worker_parts["resource_group"]))
|
||||
|
||||
if master_parts["name"].lower() != worker_parts["name"].lower():
|
||||
raise CLIError("--master-subnet vnet name '%s' must equal --worker-subnet vnet name '%s'." %
|
||||
(master_parts["name"], worker_parts["name"]))
|
||||
|
||||
if master_parts["child_name_1"].lower() == worker_parts["child_name_1"].lower():
|
||||
raise CLIError("--master-subnet name '%s' must not equal --worker-subnet name '%s'." %
|
||||
(master_parts["child_name_1"], worker_parts["child_name_1"]))
|
||||
|
||||
return resource_id(
|
||||
subscription=master_parts["subscription"],
|
||||
resource_group=master_parts["resource_group"],
|
||||
namespace='Microsoft.Network',
|
||||
type='virtualNetworks',
|
||||
name=master_parts["name"],
|
||||
)
|
||||
|
||||
|
||||
def validate_vnet(cmd, namespace):
|
||||
if namespace.vnet:
|
||||
if not is_valid_resource_id(namespace.vnet):
|
||||
if not namespace.vnet_resource_group_name:
|
||||
raise CLIError(
|
||||
"Must specify --vnet-resource-group-name if --vnet is not an id.")
|
||||
|
||||
namespace.vnet = resource_id(
|
||||
subscription=get_subscription_id(cmd.cli_ctx),
|
||||
resource_group=namespace.vnet_resource_group_name,
|
||||
namespace='Microsoft.Network',
|
||||
type='virtualNetworks',
|
||||
name=namespace.vnet,
|
||||
)
|
||||
|
||||
|
||||
def validate_worker_count(namespace):
|
||||
if namespace.worker_count:
|
||||
namespace.worker_count = _validate_int(
|
||||
"worker_count", namespace.worker_count)
|
||||
|
||||
if namespace.worker_count < 3:
|
||||
raise CLIError(
|
||||
"--worker-count must be greater than or equal to 3.")
|
||||
|
||||
|
||||
def validate_worker_vm_disk_size_gb(namespace):
|
||||
if namespace.worker_vm_disk_size_gb:
|
||||
namespace.worker_vm_disk_size_gb = _validate_int(
|
||||
"worker_vm_disk_size_gb", namespace.worker_vm_disk_size_gb)
|
||||
|
||||
if namespace.worker_vm_disk_size_gb < 128:
|
||||
raise CLIError(
|
||||
"--worker_vm_disk_size_gb must be greater than or equal to 128.")
|
||||
|
|
|
@ -1,23 +1,20 @@
|
|||
# pylint: disable=line-too-long
|
||||
from azure.cli.core.commands import CliCommandType
|
||||
from azext_aro._client_factory import cf_aro
|
||||
from azext_aro._format import aro_show_table_format
|
||||
from azext_aro._format import aro_list_table_format
|
||||
from azext_aro._help import helps # pylint: disable=unused-import
|
||||
|
||||
|
||||
def load_command_table(self, _):
|
||||
aro_sdk = CliCommandType(
|
||||
operations_tmpl='azext_aro.vendored_sdks.azure.mgmt.redhatopenshift.v2019_12_31_preview.operations#OpenShiftClustersOperations.{}', # pylint: disable=line-too-long
|
||||
client_factory=cf_aro)
|
||||
|
||||
# TODO: Add command type here
|
||||
# aro_sdk = CliCommandType(
|
||||
# operations_tmpl='<PATH>.operations#None.{}',
|
||||
# client_factory=cf_aro)
|
||||
with self.command_group('aro', aro_sdk, client_factory=cf_aro, is_preview=True) as g:
|
||||
g.custom_command('create', 'aro_create', supports_no_wait=True)
|
||||
g.custom_command('delete', 'aro_delete', supports_no_wait=True)
|
||||
g.custom_command('list', 'aro_list', table_transformer=aro_list_table_format)
|
||||
g.custom_show_command('show', 'aro_show', table_transformer=aro_show_table_format)
|
||||
g.custom_command('update', 'aro_update', supports_no_wait=True)
|
||||
|
||||
|
||||
with self.command_group('aro') as g:
|
||||
g.custom_command('create', 'create_aro')
|
||||
# g.command('delete', 'delete')
|
||||
g.custom_command('list', 'list_aro')
|
||||
# g.show_command('show', 'get')
|
||||
# g.generic_update_command('update', setter_name='update', custom_func_name='update_aro')
|
||||
|
||||
|
||||
with self.command_group('aro', is_preview=True):
|
||||
pass
|
||||
g.custom_command('get-credentials', 'aro_get_credentials')
|
||||
|
|
|
@ -1,15 +1,139 @@
|
|||
from knack.util import CLIError
|
||||
import os
|
||||
|
||||
import azext_aro.vendored_sdks.azure.mgmt.redhatopenshift.v2019_12_31_preview.models as v2019_12_31_preview
|
||||
|
||||
from azext_aro._aad import AADManager
|
||||
from azext_aro._rbac import assign_contributor_to_vnet
|
||||
from azext_aro._validators import validate_subnets
|
||||
from azure.cli.core.commands.client_factory import get_subscription_id
|
||||
from azure.cli.core.util import sdk_no_wait
|
||||
from msrestazure.azure_exceptions import CloudError
|
||||
|
||||
|
||||
def create_aro(cmd, resource_group_name, aro_name, location=None, tags=None):
|
||||
raise CLIError('TODO: Implement `aro create`')
|
||||
FP_CLIENT_ID = "f1dd0a37-89c6-4e07-bcd1-ffd3d43d8875"
|
||||
|
||||
|
||||
def list_aro(cmd, resource_group_name=None):
|
||||
raise CLIError('TODO: Implement `aro list`')
|
||||
def aro_create(cmd, # pylint: disable=too-many-locals
|
||||
client,
|
||||
resource_group_name,
|
||||
resource_name,
|
||||
master_subnet,
|
||||
worker_subnet,
|
||||
vnet=None,
|
||||
vnet_resource_group_name=None, # pylint: disable=unused-argument
|
||||
location=None,
|
||||
client_id=None,
|
||||
client_secret=None,
|
||||
pod_cidr=None,
|
||||
service_cidr=None,
|
||||
master_vm_size=None,
|
||||
worker_vm_size=None,
|
||||
worker_vm_disk_size_gb=None,
|
||||
worker_count=None,
|
||||
tags=None,
|
||||
no_wait=False):
|
||||
vnet = validate_subnets(master_subnet, worker_subnet)
|
||||
|
||||
subscription_id = get_subscription_id(cmd.cli_ctx)
|
||||
|
||||
aad = AADManager(cmd.cli_ctx)
|
||||
if client_id is None:
|
||||
app, client_secret = aad.createManagedApplication(
|
||||
"aro-%s-%s-%s" % (subscription_id, resource_group_name, resource_name))
|
||||
client_id = app.app_id
|
||||
|
||||
client_sp = aad.getServicePrincipal(client_id)
|
||||
if not client_sp:
|
||||
client_sp = aad.createServicePrincipal(client_id)
|
||||
|
||||
rp_client_id = FP_CLIENT_ID
|
||||
if rp_mode_development():
|
||||
rp_client_id = os.environ['AZURE_FP_CLIENT_ID']
|
||||
|
||||
rp_client_sp = aad.getServicePrincipal(rp_client_id)
|
||||
|
||||
assign_contributor_to_vnet(cmd.cli_ctx, vnet, client_sp.object_id)
|
||||
assign_contributor_to_vnet(cmd.cli_ctx, vnet, rp_client_sp.object_id)
|
||||
|
||||
oc = v2019_12_31_preview.OpenShiftCluster(
|
||||
location=location,
|
||||
tags=tags,
|
||||
service_principal_profile=v2019_12_31_preview.ServicePrincipalProfile(
|
||||
client_id=client_id,
|
||||
client_secret=client_secret,
|
||||
),
|
||||
network_profile=v2019_12_31_preview.NetworkProfile(
|
||||
pod_cidr=pod_cidr or "10.128.0.0/14",
|
||||
service_cidr=service_cidr or "172.30.0.0/16",
|
||||
),
|
||||
master_profile=v2019_12_31_preview.MasterProfile(
|
||||
vm_size=master_vm_size or "Standard_D8s_v3",
|
||||
subnet_id=master_subnet,
|
||||
),
|
||||
worker_profiles=[
|
||||
v2019_12_31_preview.WorkerProfile(
|
||||
name="worker", # TODO: "worker" should not be hard-coded
|
||||
vm_size=worker_vm_size or "Standard_D2s_v3",
|
||||
disk_size_gb=worker_vm_disk_size_gb or 128,
|
||||
subnet_id=worker_subnet,
|
||||
count=worker_count or 3,
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
return sdk_no_wait(no_wait, client.create,
|
||||
resource_group_name=resource_group_name,
|
||||
resource_name=resource_name,
|
||||
parameters=oc)
|
||||
|
||||
|
||||
def update_aro(cmd, instance, tags=None):
|
||||
with cmd.update_context(instance) as c:
|
||||
c.set_param('tags', tags)
|
||||
return instance
|
||||
def aro_delete(cmd, client, resource_group_name, resource_name,
|
||||
no_wait=False):
|
||||
if not no_wait:
|
||||
aad = AADManager(cmd.cli_ctx)
|
||||
try:
|
||||
oc = client.get(resource_group_name, resource_name)
|
||||
except CloudError as err:
|
||||
if err.status_code == 404:
|
||||
return
|
||||
raise err
|
||||
|
||||
sdk_no_wait(no_wait, client.delete,
|
||||
resource_group_name=resource_group_name,
|
||||
resource_name=resource_name)
|
||||
|
||||
if not no_wait:
|
||||
aad.deleteManagedApplication(oc.service_principal_profile.client_id)
|
||||
|
||||
|
||||
def aro_list(client, resource_group_name=None):
|
||||
if resource_group_name:
|
||||
return client.list_by_resource_group(resource_group_name).value
|
||||
return client.list().value
|
||||
|
||||
|
||||
def aro_show(client, resource_group_name, resource_name):
|
||||
return client.get(resource_group_name, resource_name)
|
||||
|
||||
|
||||
def aro_get_credentials(client, resource_group_name, resource_name):
|
||||
return client.get_credentials(resource_group_name, resource_name)
|
||||
|
||||
|
||||
def aro_update(client, resource_group_name, resource_name,
|
||||
worker_count=None,
|
||||
no_wait=False):
|
||||
oc = client.get(resource_group_name, resource_name)
|
||||
|
||||
if worker_count is not None:
|
||||
# TODO: [0] should not be hard-coded
|
||||
oc.worker_profiles[0].count = worker_count
|
||||
|
||||
return sdk_no_wait(no_wait, client.create,
|
||||
resource_group_name=resource_group_name,
|
||||
resource_name=resource_name,
|
||||
parameters=oc)
|
||||
|
||||
|
||||
def rp_mode_development():
|
||||
return os.environ.get('RP_MODE', '').lower() == 'development'
|
||||
|
|
|
@ -2,17 +2,16 @@ import os
|
|||
import unittest
|
||||
|
||||
from azure_devtools.scenario_tests import AllowLargeResponse
|
||||
from azure.cli.testsdk import (ScenarioTest, ResourceGroupPreparer)
|
||||
from azure.cli.testsdk import ResourceGroupPreparer
|
||||
from azure.cli.testsdk import ScenarioTest
|
||||
|
||||
|
||||
TEST_DIR = os.path.abspath(os.path.join(os.path.abspath(__file__), '..'))
|
||||
|
||||
|
||||
class AroScenarioTest(ScenarioTest):
|
||||
|
||||
@ResourceGroupPreparer(name_prefix='cli_test_aro')
|
||||
def test_aro(self, resource_group):
|
||||
|
||||
self.kwargs.update({
|
||||
'name': 'test1'
|
||||
})
|
||||
|
@ -21,15 +20,19 @@ class AroScenarioTest(ScenarioTest):
|
|||
self.check('tags.foo', 'doo'),
|
||||
self.check('name', '{name}')
|
||||
])
|
||||
|
||||
self.cmd('aro update -g {rg} -n {name} --tags foo=boo', checks=[
|
||||
self.check('tags.foo', 'boo')
|
||||
])
|
||||
|
||||
count = len(self.cmd('aro list').get_output_in_json())
|
||||
self.cmd('aro show - {rg} -n {name}', checks=[
|
||||
self.cmd('aro show -g {rg} -n {name}', checks=[
|
||||
self.check('name', '{name}'),
|
||||
self.check('resourceGroup', '{rg}'),
|
||||
self.check('tags.foo', 'boo')
|
||||
])
|
||||
|
||||
self.cmd('aro delete -g {rg} -n {name}')
|
||||
|
||||
final_count = len(self.cmd('aro list').get_output_in_json())
|
||||
self.assertTrue(final_count, count - 1)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
../../../client
|
|
@ -8,8 +8,6 @@ except ImportError:
|
|||
from distutils import log as logger
|
||||
logger.warn("Wheel is not available, disabling bdist_wheel hook")
|
||||
|
||||
# TODO: Confirm this is the right version number you want and it matches your
|
||||
# HISTORY.rst entry.
|
||||
VERSION = '0.1.0'
|
||||
|
||||
# The full list of classifiers is available at
|
||||
|
@ -28,7 +26,6 @@ CLASSIFIERS = [
|
|||
'License :: OSI Approved :: Apache Software License',
|
||||
]
|
||||
|
||||
# TODO: Add any additional SDK dependencies here
|
||||
DEPENDENCIES = [
|
||||
'azure-cli-core'
|
||||
]
|
||||
|
@ -41,12 +38,10 @@ with open('HISTORY.rst', 'r', encoding='utf-8') as f:
|
|||
setup(
|
||||
name='aro',
|
||||
version=VERSION,
|
||||
description='Microsoft Azure Command-Line Tools Aro Extension',
|
||||
# TODO: Update author and email, if applicable
|
||||
author='Microsoft Corporation',
|
||||
author_email='azpycli@microsoft.com',
|
||||
# TODO: consider pointing directly to your source code instead of the generic repo
|
||||
url='https://github.com/Azure/azure-cli-extensions',
|
||||
description='Microsoft Azure Command-Line Tools ARO Extension',
|
||||
author='Red Hat, Inc.',
|
||||
author_email='support@redhat.com',
|
||||
url='https://github.com/jim-minter/rp',
|
||||
long_description=README + '\n\n' + HISTORY,
|
||||
license='Apache',
|
||||
classifiers=CLASSIFIERS,
|
||||
|
|
Загрузка…
Ссылка в новой задаче