зеркало из 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:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
types:
|
types:
|
||||||
|
@ -21,5 +21,5 @@ jobs:
|
||||||
- name: Test
|
- name: Test
|
||||||
run: |
|
run: |
|
||||||
set -x
|
set -x
|
||||||
make test
|
make test-go
|
||||||
[[ -z "$(git status -s)" ]]
|
[[ -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
|
/*.crt
|
||||||
/*.key
|
/*.key
|
||||||
/*.pem
|
|
||||||
/*.kubeconfig
|
/*.kubeconfig
|
||||||
|
/*.pem
|
||||||
/env*
|
/env*
|
||||||
!/env.example
|
!/env.example
|
||||||
/id_rsa
|
/id_rsa
|
||||||
|
/pyenv*
|
||||||
|
/python/az/aro/build
|
||||||
|
/python/az/aro/dist
|
||||||
/rp
|
/rp
|
||||||
/secrets
|
/secrets
|
||||||
|
|
22
Makefile
22
Makefile
|
@ -3,8 +3,13 @@ COMMIT = $(shell git rev-parse --short HEAD)$(shell [[ $$(git status --porcelain
|
||||||
rp: generate
|
rp: generate
|
||||||
go build -ldflags "-X main.gitCommit=$(COMMIT)" ./cmd/rp
|
go build -ldflags "-X main.gitCommit=$(COMMIT)" ./cmd/rp
|
||||||
|
|
||||||
|
az:
|
||||||
|
cd python/az/aro && python ./setup.py bdist_egg
|
||||||
|
|
||||||
clean:
|
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
|
client: generate
|
||||||
rm -rf pkg/client python/client
|
rm -rf pkg/client python/client
|
||||||
|
@ -33,6 +38,7 @@ client: generate
|
||||||
|
|
||||||
sudo chown -R $(USER):$(USER) pkg/client python/client
|
sudo chown -R $(USER):$(USER) pkg/client python/client
|
||||||
rm -rf python/client/azure/mgmt/redhatopenshift/v2019_12_31_preview/aio
|
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
|
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:
|
secrets-update:
|
||||||
oc create secret generic aro-v4-dev --from-file=secrets --dry-run -o yaml | oc apply -f -
|
oc create secret generic aro-v4-dev --from-file=secrets --dry-run -o yaml | oc apply -f -
|
||||||
|
|
||||||
test: generate
|
test-go: generate
|
||||||
go build ./...
|
go build ./...
|
||||||
|
|
||||||
gofmt -s -w cmd hack pkg
|
gofmt -s -w cmd hack pkg
|
||||||
|
@ -63,4 +69,14 @@ test: generate
|
||||||
go vet ./...
|
go vet ./...
|
||||||
go test ./...
|
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
|
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
|
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`
|
subscription. *RH ARO engineering*: use the `osadev.cloud` zone in the `dns`
|
||||||
resource group.
|
resource group.
|
||||||
|
@ -62,15 +73,6 @@
|
||||||
*RH ARO engineering*: use the `localhost` key and certificate in the shared
|
*RH ARO engineering*: use the `localhost` key and certificate in the shared
|
||||||
`secrets/localhost.pem` file.
|
`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
|
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.
|
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_FP_CLIENT_ID: RP "first party" application client UUID
|
||||||
* AZURE_CLIENT_ID: RP AAD application client UUID
|
* AZURE_CLIENT_ID: RP AAD application client UUID
|
||||||
* AZURE_CLIENT_SECRET: RP AAD application client secret
|
* 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)
|
* 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
|
## Useful commands
|
||||||
|
|
||||||
```
|
```
|
||||||
export VNET_RESOURCEGROUP="$RESOURCEGROUP-vnet"
|
VNET_RESOURCEGROUP="$RESOURCEGROUP-vnet"
|
||||||
az group create -g "$VNET_RESOURCEGROUP" -l "$LOCATION"
|
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 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:
|
* 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-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 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:
|
* 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:
|
* 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:
|
* 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:
|
* 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:
|
* Scale a cluster:
|
||||||
|
@ -209,13 +207,13 @@ curl -k "https://localhost:8443/subscriptions/$AZURE_SUBSCRIPTION_ID/providers/M
|
||||||
```
|
```
|
||||||
COUNT=4
|
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:
|
* 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-master"
|
||||||
az network vnet subnet delete -g "$VNET_RESOURCEGROUP" --vnet-name vnet -n "$CLUSTER-worker"
|
az network vnet subnet delete -g "$VNET_RESOURCEGROUP" --vnet-name vnet -n "$CLUSTER-worker"
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
# Deploy production cluster
|
# Deploy production cluster
|
||||||
|
|
||||||
export VNET_RESOURCEGROUP=$RESOURCEGROUP-vnet
|
VNET_RESOURCEGROUP=$RESOURCEGROUP-vnet
|
||||||
|
CLUSTER=cluster
|
||||||
export CLUSTER=cluster
|
|
||||||
|
|
||||||
az group create -g "$VNET_RESOURCEGROUP" -l "$LOCATION"
|
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 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-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 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 -g "$RESOURCEGROUP" -n "$CLUSTER" --vnet-resource-group "$VNET_RESOURCEGROUP" --vnet vnet --master-subnet "$CLUSTER-master" --worker-subnet "$CLUSTER-worker"
|
||||||
|
|
||||||
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
|
|
||||||
|
|
|
@ -4,8 +4,6 @@ export RP_MODE=development
|
||||||
|
|
||||||
# RH ARO engineering: uncomment the following stanza only and run `make secrets`
|
# RH ARO engineering: uncomment the following stanza only and run `make secrets`
|
||||||
#. secrets/env
|
#. 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
|
# non-RH ARO engineering: uncomment from here
|
||||||
#export AZURE_TENANT_ID=<xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx>
|
#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_FP_CLIENT_ID=<xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx>
|
||||||
#export AZURE_CLIENT_ID=<xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx>
|
#export AZURE_CLIENT_ID=<xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx>
|
||||||
#export AZURE_CLIENT_SECRET=<secret>
|
#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>'
|
#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 azure.cli.core import AzCommandsLoader
|
||||||
|
from azure.cli.core.commands import CliCommandType
|
||||||
from azext_aro._help import helps # pylint: disable=unused-import
|
|
||||||
|
|
||||||
|
|
||||||
class AroCommandsLoader(AzCommandsLoader):
|
class AroCommandsLoader(AzCommandsLoader):
|
||||||
|
|
||||||
def __init__(self, cli_ctx=None):
|
def __init__(self, cli_ctx=None):
|
||||||
from azure.cli.core.commands import CliCommandType
|
aro_custom = CliCommandType(operations_tmpl='azext_aro.custom#{}',
|
||||||
from azext_aro._client_factory import cf_aro
|
client_factory=cf_aro)
|
||||||
aro_custom = CliCommandType(
|
|
||||||
operations_tmpl='azext_aro.custom#{}',
|
|
||||||
client_factory=cf_aro)
|
|
||||||
super(AroCommandsLoader, self).__init__(cli_ctx=cli_ctx,
|
super(AroCommandsLoader, self).__init__(cli_ctx=cli_ctx,
|
||||||
custom_command_type=aro_custom)
|
custom_command_type=aro_custom)
|
||||||
|
|
||||||
def load_command_table(self, args):
|
def load_command_table(self, args):
|
||||||
from azext_aro.commands import load_command_table
|
|
||||||
load_command_table(self, args)
|
load_command_table(self, args)
|
||||||
return self.command_table
|
return self.command_table
|
||||||
|
|
||||||
def load_arguments(self, command):
|
def load_arguments(self, command):
|
||||||
from azext_aro._params import load_arguments
|
|
||||||
load_arguments(self, command)
|
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
|
from azext_aro.custom import rp_mode_development
|
||||||
# TODO: Replace CONTOSO with the appropriate label and uncomment
|
from azext_aro.vendored_sdks.azure.mgmt.redhatopenshift.v2019_12_31_preview import AzureRedHatOpenShiftClient
|
||||||
# from azure.mgmt.CONTOSO import CONTOSOManagementClient
|
from azure.cli.core.commands.client_factory import get_mgmt_service_client
|
||||||
# return get_mgmt_service_client(cli_ctx, CONTOSOManagementClient)
|
|
||||||
return None
|
|
||||||
|
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
|
||||||
|
|
||||||
from knack.help_files import helps # pylint: disable=unused-import
|
|
||||||
|
|
||||||
|
|
||||||
helps['aro'] = """
|
helps['aro'] = """
|
||||||
type: group
|
type: group
|
||||||
short-summary: Commands to manage Aros.
|
short-summary: Manage Azure Red Hat OpenShift clusters.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
helps['aro create'] = """
|
helps['aro create'] = """
|
||||||
type: command
|
type: command
|
||||||
short-summary: Create a Aro.
|
short-summary: Create a cluster.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
helps['aro list'] = """
|
helps['aro list'] = """
|
||||||
type: command
|
type: command
|
||||||
short-summary: List Aros.
|
short-summary: List clusters.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# helps['aro delete'] = """
|
helps['aro delete'] = """
|
||||||
# type: command
|
type: command
|
||||||
# short-summary: Delete a Aro.
|
short-summary: Delete a cluster.
|
||||||
# """
|
"""
|
||||||
|
|
||||||
# helps['aro show'] = """
|
helps['aro show'] = """
|
||||||
# type: command
|
type: command
|
||||||
# short-summary: Show details of a Aro.
|
short-summary: Get the details of a cluster.
|
||||||
# """
|
"""
|
||||||
|
|
||||||
# helps['aro update'] = """
|
helps['aro update'] = """
|
||||||
# type: command
|
type: command
|
||||||
# short-summary: Update a Aro.
|
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 azext_aro._validators import validate_cidr
|
||||||
|
from azext_aro._validators import validate_client_id
|
||||||
from knack.arguments import CLIArgumentType
|
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, _):
|
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:
|
with self.argument_context('aro') as c:
|
||||||
c.argument('tags', tags_type)
|
c.argument('location',
|
||||||
c.argument('location', validator=get_default_location_from_resource_group)
|
validator=get_default_location_from_resource_group)
|
||||||
c.argument('aro_name', aro_name_type, options_list=['--name', '-n'])
|
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('client_id',
|
||||||
c.argument('aro_name', aro_name_type, id_part=None)
|
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):
|
import ipaddress
|
||||||
# Example of a storage account name or ID validator.
|
import uuid
|
||||||
# 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 azure.cli.core.commands.client_factory import get_mgmt_service_client
|
||||||
from msrestazure.tools import is_valid_resource_id, resource_id
|
from azure.cli.core.commands.client_factory import get_subscription_id
|
||||||
if namespace.storage_account:
|
from azure.cli.core.profiles import ResourceType
|
||||||
if not is_valid_resource_id(namespace.RESOURCE):
|
from knack.util import CLIError
|
||||||
namespace.storage_account = resource_id(
|
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),
|
subscription=get_subscription_id(cmd.cli_ctx),
|
||||||
resource_group=namespace.resource_group_name,
|
resource_group=namespace.vnet_resource_group_name,
|
||||||
namespace='Microsoft.Storage',
|
namespace='Microsoft.Network',
|
||||||
type='storageAccounts',
|
type='virtualNetworks',
|
||||||
name=namespace.storage_account
|
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 azure.cli.core.commands import CliCommandType
|
||||||
from azext_aro._client_factory import cf_aro
|
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, _):
|
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
|
with self.command_group('aro', aro_sdk, client_factory=cf_aro, is_preview=True) as g:
|
||||||
# aro_sdk = CliCommandType(
|
g.custom_command('create', 'aro_create', supports_no_wait=True)
|
||||||
# operations_tmpl='<PATH>.operations#None.{}',
|
g.custom_command('delete', 'aro_delete', supports_no_wait=True)
|
||||||
# client_factory=cf_aro)
|
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)
|
||||||
|
|
||||||
|
g.custom_command('get-credentials', 'aro_get_credentials')
|
||||||
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
|
|
||||||
|
|
|
@ -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):
|
FP_CLIENT_ID = "f1dd0a37-89c6-4e07-bcd1-ffd3d43d8875"
|
||||||
raise CLIError('TODO: Implement `aro create`')
|
|
||||||
|
|
||||||
|
|
||||||
def list_aro(cmd, resource_group_name=None):
|
def aro_create(cmd, # pylint: disable=too-many-locals
|
||||||
raise CLIError('TODO: Implement `aro list`')
|
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):
|
def aro_delete(cmd, client, resource_group_name, resource_name,
|
||||||
with cmd.update_context(instance) as c:
|
no_wait=False):
|
||||||
c.set_param('tags', tags)
|
if not no_wait:
|
||||||
return instance
|
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
|
import unittest
|
||||||
|
|
||||||
from azure_devtools.scenario_tests import AllowLargeResponse
|
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__), '..'))
|
TEST_DIR = os.path.abspath(os.path.join(os.path.abspath(__file__), '..'))
|
||||||
|
|
||||||
|
|
||||||
class AroScenarioTest(ScenarioTest):
|
class AroScenarioTest(ScenarioTest):
|
||||||
|
|
||||||
@ResourceGroupPreparer(name_prefix='cli_test_aro')
|
@ResourceGroupPreparer(name_prefix='cli_test_aro')
|
||||||
def test_aro(self, resource_group):
|
def test_aro(self, resource_group):
|
||||||
|
|
||||||
self.kwargs.update({
|
self.kwargs.update({
|
||||||
'name': 'test1'
|
'name': 'test1'
|
||||||
})
|
})
|
||||||
|
@ -21,15 +20,19 @@ class AroScenarioTest(ScenarioTest):
|
||||||
self.check('tags.foo', 'doo'),
|
self.check('tags.foo', 'doo'),
|
||||||
self.check('name', '{name}')
|
self.check('name', '{name}')
|
||||||
])
|
])
|
||||||
|
|
||||||
self.cmd('aro update -g {rg} -n {name} --tags foo=boo', checks=[
|
self.cmd('aro update -g {rg} -n {name} --tags foo=boo', checks=[
|
||||||
self.check('tags.foo', 'boo')
|
self.check('tags.foo', 'boo')
|
||||||
])
|
])
|
||||||
|
|
||||||
count = len(self.cmd('aro list').get_output_in_json())
|
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('name', '{name}'),
|
||||||
self.check('resourceGroup', '{rg}'),
|
self.check('resourceGroup', '{rg}'),
|
||||||
self.check('tags.foo', 'boo')
|
self.check('tags.foo', 'boo')
|
||||||
])
|
])
|
||||||
|
|
||||||
self.cmd('aro delete -g {rg} -n {name}')
|
self.cmd('aro delete -g {rg} -n {name}')
|
||||||
|
|
||||||
final_count = len(self.cmd('aro list').get_output_in_json())
|
final_count = len(self.cmd('aro list').get_output_in_json())
|
||||||
self.assertTrue(final_count, count - 1)
|
self.assertTrue(final_count, count - 1)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
../../../client
|
|
@ -8,8 +8,6 @@ except ImportError:
|
||||||
from distutils import log as logger
|
from distutils import log as logger
|
||||||
logger.warn("Wheel is not available, disabling bdist_wheel hook")
|
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'
|
VERSION = '0.1.0'
|
||||||
|
|
||||||
# The full list of classifiers is available at
|
# The full list of classifiers is available at
|
||||||
|
@ -28,7 +26,6 @@ CLASSIFIERS = [
|
||||||
'License :: OSI Approved :: Apache Software License',
|
'License :: OSI Approved :: Apache Software License',
|
||||||
]
|
]
|
||||||
|
|
||||||
# TODO: Add any additional SDK dependencies here
|
|
||||||
DEPENDENCIES = [
|
DEPENDENCIES = [
|
||||||
'azure-cli-core'
|
'azure-cli-core'
|
||||||
]
|
]
|
||||||
|
@ -41,12 +38,10 @@ with open('HISTORY.rst', 'r', encoding='utf-8') as f:
|
||||||
setup(
|
setup(
|
||||||
name='aro',
|
name='aro',
|
||||||
version=VERSION,
|
version=VERSION,
|
||||||
description='Microsoft Azure Command-Line Tools Aro Extension',
|
description='Microsoft Azure Command-Line Tools ARO Extension',
|
||||||
# TODO: Update author and email, if applicable
|
author='Red Hat, Inc.',
|
||||||
author='Microsoft Corporation',
|
author_email='support@redhat.com',
|
||||||
author_email='azpycli@microsoft.com',
|
url='https://github.com/jim-minter/rp',
|
||||||
# TODO: consider pointing directly to your source code instead of the generic repo
|
|
||||||
url='https://github.com/Azure/azure-cli-extensions',
|
|
||||||
long_description=README + '\n\n' + HISTORY,
|
long_description=README + '\n\n' + HISTORY,
|
||||||
license='Apache',
|
license='Apache',
|
||||||
classifiers=CLASSIFIERS,
|
classifiers=CLASSIFIERS,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче