diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000000..b34653c3033 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,61 @@ +# Contributing Guidelines + +The Azure Service Operator project accepts contributions via GitHub pull requests. This document outlines the process to help get your contribution accepted. + +Please see also the [Azure Service Operator Developer Guide](docs/community/developer-guide.md). + +## Contributor License Agreements + +We'd love to accept your patches! Before we can take them, we have to jump a +couple of legal hurdles. + +The [Microsoft CLA](https://cla.microsoft.com/) must be signed by all contributors. Please fill out either the individual or corporate Contributor License Agreement (CLA). Once you are CLA'ed, we'll be able to accept your pull requests. + +***NOTE***: Only original source code from you and other people that have +signed the CLA can be accepted into the repository. + +## Support Channels + +This is an open source project and as such no formal support is available. However, like all good open source projects we do offer "best effort" support through github issues. + +GitHub issues can be filed here - https://github.com/Azure/azure-service-operator/issues + +Before opening a new issue or submitting a new pull request, it's helpful to search the project - it's likely that another user has already reported the issue you're facing, or it's a known issue that we're already aware of. + +## Issues + +Issues are used as the primary method for tracking anything to do with the Azure Service Operator project. + +### Issue Lifecycle + +The issue lifecycle is mainly driven by the core maintainers, but is good information for those contributing to the project. All issue types follow the same general lifecycle. Differences are noted below. +1. Issue creation +2. Triage + - The maintainer in charge of triaging will apply the proper labels for the issue. This includes labels for priority, type, and metadata. If additional + labels are needed in the future, we will add them. + - (If needed) Clean up the title to succinctly and clearly state the issue. Also ensure that proposals are prefaced with "Proposal". +3. Discussion + - "Feature" and "Bug" issues should be connected to the PR that resolves it. + - Whoever is working on a "Feature" or "Bug" issue (whether a maintainer or someone from the community), should either assign the issue to themself or make a comment in the issue saying that they are taking it. + - "Proposal" and "Question" issues should stay open until resolved or if they have not been active for more than 30 days. This will help keep the issue queue to a manageable size and reduce noise. Should the issue need to stay open, the `keep open` label can be added. +4. Issue closure + +## How to Contribute a Patch + +1. If you haven't already done so, sign a Contributor License Agreement (see details above). +2. Fork the desired repo, develop and test your code changes. +3. Submit a pull request. + +## Reporting Security Issues + +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, including this one. + +If you believe you have found a security vulnerability in this repository that meets Microsoft's [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). + +We prefer all communications to be in English. + +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). \ No newline at end of file diff --git a/README.md b/README.md index b0b69389fb2..bcd1403e2a9 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,11 @@ [![Build Status](https://dev.azure.com/azure/azure-service-operator/_apis/build/status/Azure.azure-service-operator?branchName=master)](https://dev.azure.com/azure/azure-service-operator/_build/latest?definitionId=36&branchName=master) -> This project is experimental. Expect the API to change. It is not recommended for production environments. +> This project is experimental. The API is expected to change (while adhering to semantic versioning). It is not recommended for production environments. -## Introduction +The Azure Service Operator helps you provision Azure resources and connect your applications to them from within Kubernetes. -An Operator is an application-specific controller that extends the Kubernetes API to create, configure, and manage instances of complex stateful applications on behalf of a Kubernetes user. It builds upon the basic Kubernetes resource and controller concepts but includes domain or application-specific knowledge to automate common tasks. - -(For more details about operators, we recommend [Introducing Operators: Putting Operational Knowledge into Software](https://coreos.com/blog/introducing-operators.html)). - -This repository contains the resources and code to provision and deprovision different Azure services using a Kubernetes operator. +## Overview The Azure Operator comprises of: @@ -21,46 +17,46 @@ The project was built using [Kubebuilder](https://book.kubebuilder.io/). For more details on the control flow of the Azure Service operator, refer to the link below -[Azure Service Operator control flow](/docs/controlflow.md) - -## Install the operator - -This project maintains [releases of the Azure Service Operator](https://github.com/Azure/azure-service-operator/releases) that you can deploy via a [configurable Helm chart](./charts/azure-service-operator). +[Azure Service Operator control flow](/docs/design/controlflow.md) ## Azure Services supported -1. [Resource Group](/docs/resourcegroup/resourcegroup.md) -2. [EventHub](/docs/eventhub/eventhub.md) -3. [Azure SQL](/docs/azuresql/azuresql.md) -4. [Azure Database for PostgreSQL](/docs/postgresql/postgresql.md) -5. [Azure Database for MySQL](/docs/mysql/mysql.md) -6. [Azure Keyvault](/docs/keyvault/keyvault.md) -7. [Azure Rediscache](/docs/rediscache/rediscache.md) -8. [Storage Account](/docs/storage/storageaccount.md) -9. [Blob container](/docs/storage/blobcontainer.md) -10. [Virtual Network](/docs/virtualnetwork/virtualnetwork.md) -11. [Application Insights](/docs/appinsights/appinsights.md) -12. [API Management](/docs/apimgmt/apimgmt.md) -13. [Cosmos DB](/docs/cosmosdb/cosmosdb.md) +- [Resource Group](/docs/services/resourcegroup/resourcegroup.md) +- [EventHub](/docs/services/eventhub/eventhub.md) +- [Azure SQL](/docs/services/azuresql/azuresql.md) +- [Azure Database for PostgreSQL](/docs/services/postgresql/postgresql.md) +- [Azure Database for MySQL](/docs/services/mysql/mysql.md) +- [Azure Keyvault](/docs/services/keyvault/keyvault.md) +- [Azure Rediscache](/docs/services/rediscache/rediscache.md) +- [Storage Account](/docs/services/storage/storageaccount.md) +- [Blob container](/docs/services/storage/blobcontainer.md) +- [Virtual Network](/docs/services/virtualnetwork/virtualnetwork.md) +- [Application Insights](/docs/services/appinsights/appinsights.md) +- [API Management](/docs/services/apimgmt/apimgmt.md) +- [Cosmos DB](/docs/services/cosmosdb/cosmosdb.md) +- [Virtual Machine](/docs/services/virtualmachine/virtualmachine.md) +- [Virtual Machine Scale Set](/docs/services/vmscaleset/vmscaleset.md) -For more information on deploying, troubleshooting & deleting resources, refer to [this](/docs/customresource.md) link +## Getting started -## Building the operators +This project maintains [releases of the Azure Service Operator](https://github.com/Azure/azure-service-operator/releases) that you can deploy via a [configurable Helm chart](/charts/azure-service-operator). -You can also build, test, and run the operator from source by [following these instructions](/docs/contents.md). +For detailed instructions on getting started, go [here](docs/howto/contents.md). + +Please see the [FAQ][docs/faq.md] for answers to commonly asked questions about the Azure Service Operator ## Contributing -This project welcomes contributions and suggestions. Most contributions require you to agree to a -Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us -the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. +The [contribution guide][contribution-guide] covers everything you need to know about how you can contribute to Azure Service Operators. The [developer guide][developer-guide] will help you onboard as a developer. + +## Support + +Azure Service Operator is an open source project that is [**not** covered by the Microsoft Azure support policy](https://support.microsoft.com/en-us/help/2941892/support-for-linux-and-open-source-technology-in-azure). [Please search open issues here](https://github.com/Azure/azure-service-operator/issues), and if your issue isn't already represented please [open a new one](https://github.com/Azure/azure-service-operator/issues/new/choose). The Azure Service Operator project maintainers will respond to the best of their abilities. -When you submit a pull request, a CLA bot will automatically determine whether you need to provide -a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions -provided by the bot. You will only need to do this once across all repos using our CLA. +## Code of conduct -For more specific information on the GIT workflow and guidelines to follow, check [here](docs/contributionguidelines.md). +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information, see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). -For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or -contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. +[contribution-guide]: CONTRIBUTING.md +[developer-guide]: docs/howto/contents.md +[FAQ]: docs/faq.md diff --git a/docs/contributionguidelines.md b/docs/contributionguidelines.md deleted file mode 100644 index 3e9c593651e..00000000000 --- a/docs/contributionguidelines.md +++ /dev/null @@ -1,23 +0,0 @@ -# Contribution Workflow Guidelines - -1. You should use a [fork-and-branch](https://blog.scottlowe.org/2015/01/27/using-fork-branch-git-workflow/) strategy for contribution to this repo. - -2. During development, we will base PRs off a feature branch in the main fork, instead of master until an operator is ready. For eg, we will merge all SQL operator PRs into the branch "azure-sql" and not master. - -3. If you have changes from others as part of your PR, use "Merge commit" to merge changes instead of "Squash and Merge" and it helps retain their contribution history. - -4. Wait for the pipeline checks to succeed before merging your approved PR, to ensure tests pass. - -5. When reviewing a PR, checkout that branch and test all relevant positive/negative cases before you approve it. Do not skip the tests before approval even if time is short. - -6. We recommend smaller, more regular but logical PRs instead of a large one. It helps get feedback early and reduces chances of merge conflicts. - -7. If there are changes that require redeploying the operator, pause to think if it would impact any existing deployments and indicate this in the PR. - -8. If there are comments against your PR, make sure you either mark them as "Resolved" if addressed or comment if you disagree. It is not acceptable to re-submit a PR without acknowledging a comment. - -9. If there is someone who requests changes on your PR, please re-request review from them to make sure they get to review the updates. - -10. If you have a PR that has more than 25 commits for comments on the PR, it might be better to recreate the PR after syncing with the branch. This would help ensure the PR is more up-to-date with the branch. - -11. If there are check-ins made against your PR, make sure to do a "git pull" on your PR branch again before you test and re-send the PR. diff --git a/docs/controlflow.md b/docs/design/controlflow.md similarity index 100% rename from docs/controlflow.md rename to docs/design/controlflow.md diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 00000000000..95fb9231524 --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,15 @@ +# Azure Service Operator FAQ + +This page provides help with the most common questions about Azure Service Operators + +### Do I have to order the creation of resources through the operator? For instance, do I need to first create the EventHub namespace before creating the EventHub? +No, you can issue the creation of all resources at the same time. The operator will take care of waiting and requeing the requests until the parent resource is ready and all resources will eventually be ready. + +### If I need to add a new field to the spec of an existing CRD, do I need to increment the version of the CRD? +Yes, we follow semantic versioning to preserve backward compatibility. Please follow Kubebuilder's versioning [mechanism](https://book.kubebuilder.io/multiversion-tutorial/conversion-concepts.html) for this. + +### Is there a guide that talks about how to develop an operator for a new Azure service? +There is a step-by-step guide that walks you through this process [here](/howto/newoperatorguide.md) + +### Are there any sample apps that demonstrate how to utilize the Azure Service Operators? +We have some samples that illustrate how to use Azure Service Operators along with your application [here](https://github.com/Azure-Samples/azure-service-operator-samples). The samples also show how to utilize post-deployment-secrets from the Azure Service Operator. \ No newline at end of file diff --git a/docs/contents.md b/docs/howto/contents.md similarity index 96% rename from docs/contents.md rename to docs/howto/contents.md index 624524f074d..1db5d4674c4 100644 --- a/docs/contents.md +++ b/docs/howto/contents.md @@ -1,6 +1,6 @@ # Azure Service Operator Documentation -## Contents +## Getting Started 1. [Prereqs](prereqs.md) Find the list of tools and dependencies needed to develop and deploy the Azure Service Operator here. diff --git a/docs/debugging.md b/docs/howto/debugging.md similarity index 100% rename from docs/debugging.md rename to docs/howto/debugging.md diff --git a/docs/deploy.md b/docs/howto/deploy.md similarity index 89% rename from docs/deploy.md rename to docs/howto/deploy.md index d3e6074dcf2..290beb3fb97 100644 --- a/docs/deploy.md +++ b/docs/howto/deploy.md @@ -1,6 +1,10 @@ -# Building and deploying the Azure Service Operator +# Deploying the Azure Service Operator -## Build the operator +The easiest way to deploy the Azure Service Operator is to use Helm charts. Follow instructions [here] (helmdeploy.md) + +## Building and deploying the Azure Service Operator from source + +### Build the operator 1. Clone the repository. @@ -10,16 +14,16 @@ export GO111MODULE=on ``` -3. Log into Docker Hub and then Build the image and push it to Docker Hub. +3. Log in to your container registry, set the IMG env var, and then build and push the image. ```shell docker login - IMG=/: make build-and-push + IMG=//: make build-and-push ``` -## Deploy the operator +### Deploy the operator -**Note** You should already have a Kuberenetes cluster prerequisites [here](prereqs.md) for information on creating a Kubernetes cluster. +**Note** You should already have a Kubernetes cluster. See prerequisites [here](prereqs.md) for information on creating a Kubernetes cluster. 1. Set up the Cluster diff --git a/docs/development.md b/docs/howto/development.md similarity index 52% rename from docs/development.md rename to docs/howto/development.md index 60b13b22dfb..c9faa3db76b 100644 --- a/docs/development.md +++ b/docs/howto/development.md @@ -1,7 +1,9 @@ -# Running the Azure Service Operator in development +# Building Operator from source ## Running the operator locally +***Note: Using this method you can only install resources having the the latest version of a CRD, as there are no conversion webhooks running to convert other versions. This is the reason you need to setup test certificates using the steps below too. Use this method only to try out the operator to get familiar.*** + 1. Clone the repository into the following folder `/src/github.com/Azure`. 2. Make sure the environment variable `GO111MODULE` is set to `on`. @@ -10,7 +12,15 @@ export GO111MODULE=on ``` -3. Make sure all environment variables have been set. +3. Make sure all the below environment variables have been set appropriately. The possible values for `AZURE_CLOUD_ENV` are AzurePubliCloud (default if unspecified), AzureChinaCloud, AzureUSGovernmentCloud, AzureGermanCloud. + + ```bash + export AZURE_TENANT_ID=xxxx + export AZURE_SUBSCRIPTION_ID=xxxx + export AZURE_CLIENT_ID=xxxx + export AZURE_CLIENT_SECRET=xxxx + export AZURE_CLOUD_ENV=AzurePublicCloud + ``` 4. Install test certificates using `make generate-test-certs`. @@ -65,7 +75,7 @@ Look for the listed directory given in the *problem running manager* log entry, above that directory is: "/var/folders/1_/d50yhxgd357cfl0yjdclppfc0000gn/T/". Next, run the following command `cp -r /tmp/k8s-webhook-server /var/folders/1_/d50yhxgd357cfl0yjdclppfc0000gn/T/`. - Please note, copying the generated certificates into the this folder only needs to be done the first time (or when the local Kubernetes cluster is cleared). You do not need to do this step every time. + Please note, copying the generated certificates into the this folder only needs to be done only once (or when the machine is rebooted or the local Kubernetes cluster is cleared). You do not need to do this step every time. 7. Run the operator locally using ```make run``` @@ -107,7 +117,7 @@ 2019-09-24T12:18:10.626-0600 INFO controller-runtime.controller Starting workers {"controller": "eventhubnamespace", "worker count": 1} ``` -8. Open a new terminal window. Trigger the creation of a custom resource using kubectl and the sample YAML file provided. +8. Open a new terminal window. Trigger the creation of a custom resource using kubectl and the sample YAML file provided. For instance, you would use the following command to create a SQL server: ```shell @@ -115,7 +125,7 @@ azuresqlserver.azure.microsoft.com/sqlserver-sample created ``` -9. You should see logs on the other terminal from the operator when this custom resource is being created. +9. You should see logs on the other terminal from the operator when this custom resource is being created. ``` 2019-09-24T12:27:12.450-0600 DEBUG controller-runtime.manager.events Normal {"object": {"kind":"AzureSqlServer","namespace":"default","name":"sqlserver-sample1","uid":"ed3774af-def8-11e9-90c4-025000000001","apiVersion":"azure.microsoft.com/v1alpha1","resourceVersion":"194427"}, "reason": "Updated", "message": "finalizer azuresqlserver.finalizers.azure.com added"} @@ -180,334 +190,6 @@ To see when the Kind cluster is ready, use `docker ps -a` to list your running c For eg., use `kubectl apply -f config/samples/azure_v1alpha1_azuresqlserver.yaml` from the terminal to create a SQL server using the operator. `kubectl describe SqlServer` would show the events that indicate if the resource is created or being created. -## Step-by-Step for developing a new operator using the generic controller - -This project utilizes a generic async controller that separates out the Kubernetes controller logic from the corresponding Azure service interactions. There are a few extra steps (listed below) you will need to follow while using kubebuilder to generate a new operator. - -1. Clone the repository to your computer. Run `go mod download` to download dependencies. This may take several minutes. -2. Ensure you have `Kubebuilder` installed on your computer. -3. From the root folder of the cloned repository, run the following command: - -``` -kubebuilder create api --group azure --version v1alpha1 --kind - -kubebuilder create api --group azure --version v1alpha1 --kind AzureSQLServer -``` - -4. When you run this command, you will be prompted with two questions. Answer yes to both of these. - -This will create - -- a CRD types file in /api/v1alpha1 -- a controller file in controllers/{resource_type}_controller.go -- and other needed scaffolding. - -``` -➜ azure-service-operator git:(testbranch) ✗ kubebuilder create api --group azure --version v1alpha1 --kind AzureNewType -Create Resource [y/n] -y -Create Controller [y/n] -y -Writing scaffold for you to edit... -api/v1alpha1/azurenewtype_types.go -controllers/azurenewtype_controller.go -Running make... -make: kind: Command not found -/bin/sh: kind: command not found -go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.2.0 -go: finding sigs.k8s.io/controller-tools/cmd/controller-gen v0.2.0 -go: finding sigs.k8s.io/controller-tools/cmd v0.2.0 -go: finding sigs.k8s.io v0.2.0 -/Users/jananiv/go/bin/controller-gen "crd:trivialVersions=true" rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases -/Users/jananiv/go/bin/controller-gen object:headerFile=./hack/boilerplate.go.txt paths=./api/... -go fmt ./... -go vet ./... -go build -o bin/manager main.go -``` - -5. *Updating the types file* - - Open the `AzureNewType_types.go` file that was generated under `api/v1alpha1`. - a. Replace the generated `Status` struct with the shared `ASOStatus` from `/api/{version}/aso_types.go` as below - - ```go - type AzureNewType struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec AzureNewTypeSpec `json:"spec,omitempty"` - Status ASOStatus `json:"status,omitempty"` - } - ``` - - b. Define the fields for the `AzureNewTypeSpec` struct. This will be all the parameters that you will need to create a resource of type `AzureNewType`. - - For instance, if I need to create a resource of type ResourceGroup, I need a Subscription ID, Name, and a Location. - - The `Subscription ID` is something we configure through config for the entire operator, so it can be omitted. - The `Name` for every resource is going to be the Kubernetes `Metadata.Name` we pass in the manifest, so omit that from the Spec as well. - In this case you would only add `Location` of type `string` to the Spec. - - Here is an example of how this might look. Note that we use camel case for the names of the fields in the json specification. - - ```go - type AzureNewTypeSpec struct { - Location string `json:"location"` - ResourceGroup string `json:"resourceGroup,omitempty"` - } - ``` - - You can refer to the other types in this repo as examples to do this. - - c. Add the Kubebuilder directive to indicate that you want to treat `Status` as a subresource of the CRD. This allows for more efficient updates and the generic controller assumes that this is enabled for all the types. - - ```go - // +kubebuilder:object:root=true - // +kubebuilder:subresource:status <--- This is the line we need to add - - // AzureNewType is the Schema for the azurenewtypes API - type AzureNewType struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec AzureNewTypeSpec `json:"spec,omitempty"` - Status AzureNewTypeStatus `json:"status,omitempty"` - } - ``` - -6. *Updating the generated controller file* - - Open the `azurenewtype_controller.go` file generated under the `controllers` directory. - a. Update the `AzureNewTypeReconciler` struct by removing the fields in there and replacing it with the below. - - ```go - // AzureNewTypeReconciler reconciles a AzureNewType object - type AzureNewTypeReconciler struct { - Reconciler *AsyncReconciler - } - ``` - - b. Update the `Reconcile` function code in this file to the following: - - ```go - // +kubebuilder:rbac:groups=azure.microsoft.com,resources=azurenewtypes,verbs=get;list;watch;create;update;patch;delete - // +kubebuilder:rbac:groups=azure.microsoft.com,resources=azurenewtypes/status,verbs=get;update;patch - - func (r *AzureNewTypeReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { - return r.Reconciler.Reconcile(req, &azurev1alpha1.AzureNewType{}) - } - ``` - -7. *Updating the sample YAML file* - - Open the `azure_v1alpha1_azurenewtype.yaml` file under `config/samples`. - Update the spec portion of this file with the fields that you added to the Spec in step 5b above with corresponding values. - - Refer to the other sample YAML files in the repo for how to do this correctly. - -8. *Implementing the actual resource creation/deletion logic* - - This is the service specific piece that differs from one Azure service to another, and the crux of the service provisioning/deletion logic used by the controller. - - **Note** Please make sure that you make all creation and deletion calls to Azure are asynchronous. - - a. The guidance is to add a folder under `pkg/resourcemanager` for the new resource, like for instance, `pkg/resourcemanager/newresource` - - b. Use subfolders under this folder if you have subresources. For instance, for PostgreSQL we have separate sub folders for `server`, `database` and `firewallrule` - - c. Add these files under this folder - azurenewtype_manager.go - azurenewtype_reconcile.go - azurenewtype.go - - d. The `azurenewtype_manager.go` file would implement the interface that includes the ARMClient as follows, and in addition have any other functions you need for Create, Delete, and Get of the resource. - - ```go - type AzureNewTypeManager interface { - // Functions for Create, Delete and Get for the resource as needed - - // also embed async client methods - resourcemanager.ARMClient - } - - ``` - - The `azurenewtype.go` file defines a struct that implements the `AzureNewTypeManager` interface. It has the definitions of the Create, Delete and Get functions included in the interface in the `azurenewtype_manager.go` - - Here is an example of what this struct looks like. - - **Note** Don't add a logger to this struct. Return all errors from this file to the controller so we can log it there. - - ```go - type AzureNewTypeClient struct {} - - func NewAzureNewTypeClient() *AzureNewTypeClient { - return &AzureNewTypeClient{} - } - ``` - - e. The `azurenewtype_reconcile.go` file implements the following functions in the ARMClient interface: - - `Ensure`, `Delete`, `GetParents`, `GetStatus` - - It would also have a `convert` function to convert the runtime object into the appropriate type - - Some key points to note: - (i) The Ensure and Delete functions return as the first return value, a bool which indicates if the resource was found in Azure. So Ensure() if successful would return `true` and Delete() if successful would return `false` - - (ii) On successful provisioning in `Ensure()`, - - set instance.Status.Message to the constant `SuccessMsg` in the `resourcemanager` package to be consistent across all controllers. - - set instance.Status.ResourceID to the full Azure Resource ID of the resource - - set instance.Status.Provisioned to `true` and instance.Status.Provisioning to `false` - - ```go - func (p *AzureNewTypeClient) Ensure(ctx context.Context, obj runtime.Object) (found bool, err error) { - instance, err := p.convert(obj) - if err != nil { - return true, err - } - // Add logic to idempotently create the resource - - // successful return - return true, nil - } - - func (p *AzureNewTypeClient) Delete(ctx context.Context, obj runtime.Object) (found bool, err error) { - instance, err := p.convert(obj) - if err != nil { - return true, err - } - // Add logic to idempotently delete the resource - - // successful return - return false, nil - } - ``` - - (ii) The `GetParents()` function returns the Azure Resource Manager (ARM) hierarchy of the resource. The order here matters - the immediate hierarchical resource should be returned first. For instance, for an Azure SQL database, the first parent should be Azure SQL server followed by the Resource Group. - - An example is shown below: - - ```go - func (p *AzureNewTypeClient) GetParents(obj runtime.Object) ([]resourcemanager.KubeParent, error) { - - instance, err := p.convert(obj) - if err != nil { - return nil, err - } - - // Update this based on the resource to add other parents - - return []resourcemanager.KubeParent{ - { - Key: types.NamespacedName{ - Namespace: instance.Namespace, - Name: instance.Spec.ResourceGroup, - }, - Target: &azurev1alpha1.ResourceGroup{}, - }, - }, nil - } - ``` - - (iii) The `GetStatus()` is a boilerplate function, use the below function and alter to use the struct you attach the function to. - - ```go - func (p *AzureNewTypeClient) GetStatus(obj runtime.Object) (*v1alpha1.ASOStatus, error) { - instance, err := g.convert(obj) - if err != nil { - return nil, err - } - return &instance.Status, nil - } - ``` - - (iv) The `convert()` function looks like the below, use the correct type based on the controller you are implementing. - - ```go - func (p *AzureNewTypeClient) convert(obj runtime.Object) (*v1alpha1.AzureNewType, error) { - local, ok := obj.(*v1alpha1.AzureNewType) - if !ok { - return nil, fmt.Errorf("failed type assertion on kind: %s", obj.GetObjectKind().GroupVersionKind().String()) - } - return local, nil - } - ``` - -9. *Tests* - - Add the following tests for your new operator: - (i) Unit test for the new type: You will add this as a file named `azurenewtype_types_test.go` under `api/v1alpha`. Refer to the existing tests in the repository to author this for your new type. - - (ii) Controller tests: This will be a file named `azurenewresourcetype_controller_test.go` under the `controllers` folder. Refer to the other controller tests in the repo for how to write this test. This test validates the new controller to make sure the resource is created and deleted in Kubernetes effectively. - -10. *Instantiating the reconciler* - - The last step to tie everything together is to ensure that your new controller's reconciler is instantiated in both the `main.go` and the `suite_test.go` (under `controllers` folder) files. - - ```go - main.go - - if err = (&controllers.AzureNewResourceTypeReconciler{ - Reconciler: &controllers.AsyncReconciler{ - Client: mgr.GetClient(), - AzureClient: , - Telemetry: telemetry.InitializePrometheusDefault( - ctrl.Log.WithName("controllers").WithName("AzureNewResourceType"), - "AzureNewResourceType", - ), - Recorder: mgr.GetEventRecorderFor("AzureNewResourceType-controller"), - Scheme: scheme, - }, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "AzureNewResourceType") - os.Exit(1) - } - ``` - - ```go - suite_test.go - - err = (&AzureNewResourceTypeReconciler{ - Reconciler: &AsyncReconciler{ - Client: k8sManager.GetClient(), - AzureClient: , - Telemetry: telemetry.InitializePrometheusDefault( - ctrl.Log.WithName("controllers").WithName("AzureNewResourceType"), - "AzureNewResourceType", - ), - Recorder: k8sManager.GetEventRecorderFor("AzureNewResourceType-controller"), - Scheme: k8sManager.GetScheme(), - }, - }).SetupWithManager(k8sManager) - Expect(err).ToNot(HaveOccurred()) - ``` - -11. Install the new CRD and generate the manifests needed using the following commands. This is required in order to generate canonical resource definitions (manifests as errors about a DeepCopyObject() method missing). - - ``` - make generate - make manifests - make install - ``` - - Run controller tests using `make test-existing-controllers` and deploy using `make deploy` - - If you make changes to the operator and want to update the deployment without recreating the cluster (when testing locally), you can use the `make update` to update your Azure Operator pod. If you need to rebuild the docker image without cache, use `make ARGS="--no-cache" update` - -12. Update the Helm Chart to include the new CRD. - Run: - ``` - make helm-chart-manifests - make delete-helm-gen-manifests - ``` - - This will generate the manifests into the Helm Chart directory, and repackage them into a new Helm Chart tar.gz file. Add the newly modified files to the PR, which should be the following: - ``` - charts/azure-service-operator-0.1.0.tgz - charts/index.yaml - ``` - -**Notes:** - -- Run `make manifests` if you find the property you add doesn't work. +## Want to contribute a new operator? -- Finalizers are recommended as they make deleting a resource more robust. Refer to [Using Finalizers](https://book.kubebuilder.io/reference/using-finalizers.html) for more information +If you are ready to contribute a new operator to the Azure Service Operators project, please follow the step-by-step guide [here](newoperatorguide.md) \ No newline at end of file diff --git a/docs/howto/helmdeploy.md b/docs/howto/helmdeploy.md new file mode 100644 index 00000000000..417fb908702 --- /dev/null +++ b/docs/howto/helmdeploy.md @@ -0,0 +1,119 @@ +## Deploy using Helm charts + +### Installing + +#### Pre-Install + +This Helm chart contains certificates that depend on [cert-manager](https://cert-manager.io/docs/installation/kubernetes/) to be installed. Install cert-manager prior to installing chart: + +``` +kubectl create namespace cert-manager +kubectl label namespace cert-manager cert-manager.io/disable-validation=true +kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v0.12.0/cert-manager.yaml +``` + +You can use the below command to check if the cert manager pods are ready. The cert manager pods should be running before proceeding to the next step. + +``` +kubectl rollout status -n cert-manager deploy/cert-manager-webhook +``` + +#### Helm + +Install the latest (3.x+) [Helm](https://helm.sh/docs/intro/install/) on your machine. + +Add the helm repo: +```console +helm repo add azureserviceoperator https://raw.githubusercontent.com/Azure/azure-service-operator/master/charts --username --password +``` + +### Getting Started + +Copy the `values.yaml` file from this directory and in the following steps fill in the requisite values. + +First, set the following variables to your Azure Tenant ID and Subscription ID: +``` +azureTenantID: 00000000-0000-0000-0000-000000000000 +azureSubscriptionID: 00000000-0000-0000-0000-000000000000 +``` + +#### Authentication + +Next, choose one of the following authentication methods, and set its appropriate variables. + +##### Service Principal + +Set the following variables to your client ID and secret values: +``` +azureClientID: 00000000-0000-0000-0000-000000000000 +azureClientSecret: 00000000-0000-0000-0000-000000000000 +``` + +##### Managed Identity + +Set the following Helm Chart values: +``` +azureUseMI: True +aad-pod-identity: + azureIdentity: + resourceID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups//providers/Microsoft.ManagedIdentity/userAssignedIdentities/" + clientID: "00000000-0000-0000-0000-000000000000" +``` + +Follow the instructions [here](../../docs/deploy.md) to create an identity and assign it the correct permissions. + +#### Keyvault + +By default, secrets will be stored as Kubernetes secrets. If you wish to store them in KeyVault instead, follow the instructions [here](../../docs/deploy.md). + +Then, set the following chart value to your KeyVault name: +``` +azureOperatorKeyvault: OperatorSecretKeyVault +``` + +#### Install Chart + +If you are deploying into an already created namespace, be sure to set the following variable to false: +``` +createNamespace: False +``` + +and specify the namespace name: +``` +namespace: your-namespace +``` + +Finally, install the chart with your added values. The chart can be installed by using a values file or environment variables. +``` +helm upgrade --install aso azureserviceoperator/azure-service-operator -f values.yaml +``` + +``` +helm upgrade --install aso azureserviceoperator/azure-service-operator \ + --set azureSubscriptionID=$AZURE_SUBSCRIPTION_ID \ + --set azureTenantID=$AZURE_TENANT_ID \ + --set azureClientID=$AZURE_CLIENT_ID \ + --set azureClientSecret=$AZURE_CLIENT_SECRET \ + --set azureUseMI=$AZURE_USE_MI \ + --set azureOperatorKeyvault=$AZURE_OPERATOR_KEYVAULT \ + --set createNamespace=False +``` + +### Configuration + +The following table lists the configurable parameters of the azure-service-operator chart and its dependency chart, aad-pod-identity. + +| Parameter | Description | Default | +|:---------------------------|:-------------------------|:---------------------| +| `azureSubscriptionID` | Azure Subscription ID | `` | +| `azureTenantID` | Azure Tenant ID | `` | +| `azureClientID` | Azure Service Principal Client ID | `` | +| `azureClientSecret` | Azure Service Principal Client Secret | `` | +| `azureUseMI` | Set to True if using Managed Identity for authentication | `False` | +| `azureOperatorKeyvault` | Set this value with the name of your Azure Key Vault resource if you prefer to store secrets in Key Vault rather than as Kubernetes secrets (default) | `` | +| `image.repository` | Image repository | `mcr.microsoft.com/k8s/azure-service-operator:0.0.20258` | +| `cloudEnvironment` | Set the cloud environment, possible values include: AzurePublicCloud, AzureUSGovernmentCloud, AzureChinaCloud, AzureGermanCloud | `AzurePublicCloud` | +| `createNamespace` | Set to True if you would like the namespace autocreated, otherwise False if you have an existing namespace. If using an existing namespace, the `namespace` field must also be updated | `True` | +| `namespace` | Configure a custom namespace to deploy the operator into | `azureoperator-system` | +| `aad-pod-identity.azureIdentity.resourceID` | The resource ID for your managed identity | `` | +| `aad-pod-identity.azureIdentity.clientID` | The client ID for your managed identity | `` | diff --git a/docs/howto/managedidentity.md b/docs/howto/managedidentity.md new file mode 100644 index 00000000000..5bf17c2299a --- /dev/null +++ b/docs/howto/managedidentity.md @@ -0,0 +1,89 @@ +# Using Managed Identity for authentication in the operator + +Perform these steps to use Managed Identity instead of Service Principal authentication in the operator. + +1. Create a managed identity in a specified resource group within your subscription. +2. Give the Service Principal associated with the AKS cluster control over managing the identity we just created. +3. Give the Managed Identity we just created authorization to provision resources in our subscription + +You can accomplish all of the above 3 steps using the script [here](./../../cli/main.go) + +Run the script as follows: + +``` +go run cli/main.go createmi \ + -g resourcegroup_name \ + -i managed_identity_name \ + -p aks_cluster_service_principal_id \ + --subscription sub_id +``` + +*resourcegroup_name* = Resource Group where you want to create the Managed Identity +*managed_identity_name* = Name of the Managed Identity to create +*sub_id* = Subscription Id +*aks_cluster_service_principal_id* = Principal Id of your AKS cluster's identity + +For an AKS cluster with Service Principal, this is: +```az aks show -g -n --query servicePrincipalProfile.clientId -otsv``` + +for an AKS cluster with Managed Identity, this is: +```az aks show -g -n --query identityProfile.kubeletidentity.clientId -otsv``` + +You will see the script run some commands and then will output the next steps to perform as below. + +```bash +Install AAD Pod Identity: +make install-aad-pod-identity + +cat < + +# e.g. kubebuilder create api --group azure --version v1alpha1 --kind AzureSQLServer +``` + +4. When you run this command, you will be prompted with two questions. Answer yes to both of these. + +This will create + +- a CRD types file in /api/v1alpha1 +- a controller file in controllers/{resource_type}_controller.go +- and other needed scaffolding. + +``` +➜ azure-service-operator git:(testbranch) ✗ kubebuilder create api --group azure --version v1alpha1 --kind AzureNewType +Create Resource [y/n] +y +Create Controller [y/n] +y +Writing scaffold for you to edit... +api/v1alpha1/azurenewtype_types.go +controllers/azurenewtype_controller.go +Running make... +make: kind: Command not found +/bin/sh: kind: command not found +go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.2.0 +go: finding sigs.k8s.io/controller-tools/cmd/controller-gen v0.2.0 +go: finding sigs.k8s.io/controller-tools/cmd v0.2.0 +go: finding sigs.k8s.io v0.2.0 +/Users/jananiv/go/bin/controller-gen "crd:trivialVersions=true" rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases +/Users/jananiv/go/bin/controller-gen object:headerFile=./hack/boilerplate.go.txt paths=./api/... +go fmt ./... +go vet ./... +go build -o bin/manager main.go +``` + +5. *Updating the types file* + + Open the `AzureNewType_types.go` file that was generated under `api/v1alpha1`. + a. Replace the generated `Status` struct with the shared `ASOStatus` from `/api/{version}/aso_types.go` as below + + ```go + type AzureNewType struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec AzureNewTypeSpec `json:"spec,omitempty"` + Status ASOStatus `json:"status,omitempty"` + } + ``` + + b. Define the fields for the `AzureNewTypeSpec` struct. This will be all the parameters that you will need to create a resource of type `AzureNewType`. + + For instance, if I need to create a resource of type ResourceGroup, I need a Subscription ID, Name, and a Location. + + The `Subscription ID` is something we configure through config for the entire operator, so it can be omitted. + The `Name` for every resource is going to be the Kubernetes `Metadata.Name` we pass in the manifest, so omit that from the Spec as well. + In this case you would only add `Location` of type `string` to the Spec. + + Here is an example of how this might look. Note that we use camel case for the names of the fields in the json specification. + + ```go + type AzureNewTypeSpec struct { + Location string `json:"location"` + ResourceGroup string `json:"resourceGroup,omitempty"` + } + ``` + + You can refer to the other types in this repo as examples to do this. + + c. Add the Kubebuilder directive to indicate that you want to treat `Status` as a subresource of the CRD. This allows for more efficient updates and the generic controller assumes that this is enabled for all the types. + Also add the Kubebuilder directives to designate short names for the CRD and to add additional columns to the output of `kubectl get`. + + ```go + // +kubebuilder:object:root=true + // +kubebuilder:subresource:status <--- This is the line we need to add + + // +kubebuilder:resource:shortName=[shortnamehere],path=[crdpath] + // +kubebuilder:printcolumn:name="Provisioned",type="string",JSONPath=".status.provisioned" + // +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.message" + + // AzureNewType is the Schema for the azurenewtypes API + type AzureNewType struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec AzureNewTypeSpec `json:"spec,omitempty"` + Status AzureNewTypeStatus `json:"status,omitempty"` + } + ``` + +6. *Updating the generated controller file* + + Open the `azurenewtype_controller.go` file generated under the `controllers` directory. + a. Update the `AzureNewTypeReconciler` struct by removing the fields in there and replacing it with the below. + + ```go + // AzureNewTypeReconciler reconciles a AzureNewType object + type AzureNewTypeReconciler struct { + Reconciler *AsyncReconciler + } + ``` + + b. Update the `Reconcile` function code in this file to the following: + + ```go + // +kubebuilder:rbac:groups=azure.microsoft.com,resources=azurenewtypes,verbs=get;list;watch;create;update;patch;delete + // +kubebuilder:rbac:groups=azure.microsoft.com,resources=azurenewtypes/status,verbs=get;update;patch + + func (r *AzureNewTypeReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { + return r.Reconciler.Reconcile(req, &azurev1alpha1.AzureNewType{}) + } + ``` + +7. *Updating the sample YAML file* + + Open the `azure_v1alpha1_azurenewtype.yaml` file under `config/samples`. + Update the spec portion of this file with the fields that you added to the Spec in step 5b above with corresponding values. + + Refer to the other sample YAML files in the repo for how to do this correctly. + +8. *Implementing the actual resource creation/deletion logic* + + This is the service specific piece that differs from one Azure service to another, and the crux of the service provisioning/deletion logic used by the controller. + + **Note** Please make sure that you make all creation and deletion calls to Azure are asynchronous. + + a. The guidance is to add a folder under `pkg/resourcemanager` for the new resource, like for instance, `pkg/resourcemanager/newresource` + + b. Use subfolders under this folder if you have subresources. For instance, for PostgreSQL we have separate sub folders for `server`, `database` and `firewallrule` + + c. Add these files under this folder + azurenewtype_manager.go + azurenewtype_reconcile.go + azurenewtype.go + + d. The `azurenewtype_manager.go` file would implement the interface that includes the ARMClient as follows, and in addition have any other functions you need for Create, Delete, and Get of the resource. + + ```go + type AzureNewTypeManager interface { + // Functions for Create, Delete and Get for the resource as needed + + // also embed async client methods + resourcemanager.ARMClient + } + + ``` + + The `azurenewtype.go` file defines a struct that implements the `AzureNewTypeManager` interface. It has the definitions of the Create, Delete and Get functions included in the interface in the `azurenewtype_manager.go` + + Here is an example of what this struct looks like. + + **Note** Don't add a logger to this struct. Return all errors from this file to the controller so we can log it there. + + ```go + type AzureNewTypeClient struct {} + + func NewAzureNewTypeClient() *AzureNewTypeClient { + return &AzureNewTypeClient{} + } + ``` + + e. The `azurenewtype_reconcile.go` file implements the following functions in the `ARMClient` interface: + - `Ensure`, `Delete`, `GetParents`, `GetStatus` + - It would also have a `convert` function to convert the runtime object into the appropriate type + + Some key points to note: + (i) The Ensure and Delete functions return as the first return value, a bool which indicates if the resource was found in Azure. So Ensure() if successful would return `true` and Delete() if successful would return `false` + + (ii) On successful provisioning in `Ensure()`, + - set `instance.Status.Message` to the constant `SuccessMsg` in the `resourcemanager` package to be consistent across all controllers. + - set `instance.Status.ResourceID` to the full Azure Resource ID of the resource + - set `instance.Status.Provisioned` to `true` and `instance.Status.Provisioning` to `false` + + ```go + func (p *AzureNewTypeClient) Ensure(ctx context.Context, obj runtime.Object) (found bool, err error) { + instance, err := p.convert(obj) + if err != nil { + return true, err + } + // Add logic to idempotently create the resource + + // successful return + return true, nil + } + + func (p *AzureNewTypeClient) Delete(ctx context.Context, obj runtime.Object) (found bool, err error) { + instance, err := p.convert(obj) + if err != nil { + return true, err + } + // Add logic to idempotently delete the resource + + // successful return + return false, nil + } + ``` + + (ii) The `GetParents()` function returns the Azure Resource Manager (ARM) hierarchy of the resource. The order here matters - the immediate hierarchical resource should be returned first. For instance, for an Azure SQL database, the first parent should be Azure SQL server followed by the Resource Group. + + An example is shown below: + + ```go + func (p *AzureNewTypeClient) GetParents(obj runtime.Object) ([]resourcemanager.KubeParent, error) { + + instance, err := p.convert(obj) + if err != nil { + return nil, err + } + + // Update this based on the resource to add other parents + + return []resourcemanager.KubeParent{ + { + Key: types.NamespacedName{ + Namespace: instance.Namespace, + Name: instance.Spec.ResourceGroup, + }, + Target: &azurev1alpha1.ResourceGroup{}, + }, + }, nil + } + ``` + + (iii) The `GetStatus()` is a boilerplate function, use the below function and alter to use the struct you attach the function to. + + ```go + func (p *AzureNewTypeClient) GetStatus(obj runtime.Object) (*v1alpha1.ASOStatus, error) { + instance, err := g.convert(obj) + if err != nil { + return nil, err + } + return &instance.Status, nil + } + ``` + + (iv) The `convert()` function looks like the below, use the correct type based on the controller you are implementing. + + ```go + func (p *AzureNewTypeClient) convert(obj runtime.Object) (*v1alpha1.AzureNewType, error) { + local, ok := obj.(*v1alpha1.AzureNewType) + if !ok { + return nil, fmt.Errorf("failed type assertion on kind: %s", obj.GetObjectKind().GroupVersionKind().String()) + } + return local, nil + } + ``` + +9. *Tests* + + Add the following tests for your new operator: + (i) Unit test for the new type: You will add this as a file named `azurenewtype_types_test.go` under `api/v1alpha`. Refer to the existing tests in the repository to author this for your new type. + + (ii) Controller tests: This will be a file named `azurenewresourcetype_controller_test.go` under the `controllers` folder. Refer to the other controller tests in the repo for how to write this test. This test validates the new controller to make sure the resource is created and deleted in Kubernetes effectively. + +10. *Instantiating the reconciler* + + The last step to tie everything together is to ensure that your new controller's reconciler is instantiated in both the `main.go` and the `suite_test.go` (under `controllers` folder) files. + + ```go + main.go + + if err = (&controllers.AzureNewResourceTypeReconciler{ + Reconciler: &controllers.AsyncReconciler{ + Client: mgr.GetClient(), + AzureClient: , + Telemetry: telemetry.InitializePrometheusDefault( + ctrl.Log.WithName("controllers").WithName("AzureNewResourceType"), + "AzureNewResourceType", + ), + Recorder: mgr.GetEventRecorderFor("AzureNewResourceType-controller"), + Scheme: scheme, + }, + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "AzureNewResourceType") + os.Exit(1) + } + ``` + + ```go + suite_test.go + + err = (&AzureNewResourceTypeReconciler{ + Reconciler: &AsyncReconciler{ + Client: k8sManager.GetClient(), + AzureClient: , + Telemetry: telemetry.InitializePrometheusDefault( + ctrl.Log.WithName("controllers").WithName("AzureNewResourceType"), + "AzureNewResourceType", + ), + Recorder: k8sManager.GetEventRecorderFor("AzureNewResourceType-controller"), + Scheme: k8sManager.GetScheme(), + }, + }).SetupWithManager(k8sManager) + Expect(err).ToNot(HaveOccurred()) + ``` + +11. Install the new CRD and generate the manifests needed using the following commands. This is required in order to generate canonical resource definitions (manifests as errors about a DeepCopyObject() method missing). + + ``` + make generate + make manifests + make install + ``` + + Run controller tests using `make test-existing-controllers` and deploy using `make deploy` + + If you make changes to the operator and want to update the deployment without recreating the cluster (when testing locally), you can use the `make update` to update your Azure Operator pod. If you need to rebuild the docker image without cache, use `make ARGS="--no-cache" update` + +12. Update the Helm Chart to include the new CRD. + Run: + ``` + make helm-chart-manifests + make delete-helm-gen-manifests + ``` + + This will generate the manifests into the Helm Chart directory, and repackage them into a new Helm Chart tar.gz file. Add the newly modified files to the PR, which should be the following: + ``` + charts/azure-service-operator-0.1.0.tgz + charts/index.yaml + ``` + +**Notes:** + +- Run `make manifests` if you find the property you add doesn't work. + +- Finalizers are recommended as they make deleting a resource more robust. Refer to [Using Finalizers](https://book.kubebuilder.io/reference/using-finalizers.html) for more information diff --git a/docs/prereqs.md b/docs/howto/prereqs.md similarity index 51% rename from docs/prereqs.md rename to docs/howto/prereqs.md index 5d24581c8c0..b3cbc9622d9 100644 --- a/docs/prereqs.md +++ b/docs/howto/prereqs.md @@ -3,7 +3,7 @@ 1. [GoLang](https://golang.org/dl/) is installed. 2. [Docker](https://docs.docker.com/install/) is installed and running. 3. [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) Command-line tool is installed. -4. A Kubernetes cluster. +4. A Kubernetes cluster. Can be any of the following but an AKS cluster is recommended for testing RBAC and multiple CRD versions (as webhooks are required) - Local: [Minikube](https://kubernetes.io/docs/tasks/tools/install-minikube) - [Kind](https://github.com/kubernetes-sigs/kind), or, - [Docker for desktop](https://blog.docker.com/2018/07/kubernetes-is-now-available-in-docker-desktop-stable-channel/). @@ -13,38 +13,19 @@ 6. [Kustomize](https://github.com/kubernetes-sigs/kustomize) (This may be installed via `make install-kustomize`) -7. Create a Service Principal. - If you don't have a Service Principal create one from Azure CLI: +7. Create an identity for running the Operator as - Managed Identity or Service Principal. - ```bash - az ad sp create-for-rbac --role Contributor - ``` - - Then make sure this service principal has rights assigned to provision resources in your Azure Subscription and Resource Group. - -8. Set the environment variables `AZURE_TENANT_ID`, `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, `AZURE_SUBSCRIPTION_ID`, `REQUEUE_AFTER`. +``` +az ad sp create-for-rbac --name ServicePrincipalName +``` - ```shell - export AZURE_TENANT_ID=xxxxxxx - export AZURE_CLIENT_ID=yyyyyyy - export AZURE_CLIENT_SECRET=zzzzzz - export AZURE_SUBSCRIPTION_ID=aaaaaaa - export REQUEUE_AFTER=30 - ``` - - If running on Windows, the environment variables should not have quotes and should be set like below. - - ```shell - set AZURE_TENANT_ID=xxxxxxx - set AZURE_CLIENT_ID=yyyyyyy - set AZURE_CLIENT_SECRET=zzzzzz - set AZURE_SUBSCRIPTION_ID=aaaaaaa - set REQUEUE_AFTER=30 - ``` +``` +az identity create -g ResourceGroup -n ManagedIdentityName --subscription SubscriptionId +``` - VSCode or `make run` should be run from the same session/command/terminal window where the environment variables are set. +Then make sure this identity has rights assigned to provision resources in your Azure Subscription and Resource Group. -9. Basic commands to check if you have an active Kubernetes cluster: +8. Basic commands to check if you have an active Kubernetes cluster: ```shell kubectl config get-contexts diff --git a/docs/howto/testing.md b/docs/howto/testing.md new file mode 100644 index 00000000000..97b72033d1e --- /dev/null +++ b/docs/howto/testing.md @@ -0,0 +1,17 @@ +# Testing + +Testing can be done in the following ways: + +- `make test-integration-controllers` - Test the controllers end-to-end against Azure. You will need to have an active Kubernetes Cluster and run `make install` before running the tests. + +This is the most exhaustive and recommended way to test the controllers. + +The controller test suite has included Go Build Tags to allow selectively running tests. Users can specify individual test suites by setting the `BUILD_TAGS` parameter as an environment variable or before the make target: `make BUILD_TAGS=azuresqlservercombined test-integration-controllers`. Test files declare their tags in the `// +build` comment at the top of the file. + +- `make test-integration-managers` - Test the Azure SDK resource managers against an existing cluster. This tests the Azure APIs but does not test the Kubernetes controllers. + +- `make test-unit` - Runs the API and resource manager unit tests. + +## Pipeline test runs + +The controller test suite is run in against all PRs as part of the continuous integration pipeline. \ No newline at end of file diff --git a/docs/images/debugging.gif b/docs/images/debugging.gif deleted file mode 100644 index 50c585bd261..00000000000 Binary files a/docs/images/debugging.gif and /dev/null differ diff --git a/docs/managedidentity.md b/docs/managedidentity.md deleted file mode 100644 index 40b4bf474ef..00000000000 --- a/docs/managedidentity.md +++ /dev/null @@ -1,73 +0,0 @@ -# Using Managed Identity for authentication in the operator - -Perform these steps to use Managed Identity instead of Service Principal authentication in the operator. - -1. Create an identity that will be able to manage resources in the specified resource group. - - ```shell - az identity create -g -n aso-manager-identity -o json - ``` - - This command will have an output like the below - - ```shell - { - "clientId": "288a7d63-ab78-442e-89ee-2a353fb990ab", - "clientSecretUrl": "https://control-westus.identity.azure.net/subscriptions/7060bca0-7a3c-44bd-b54c-4bb1e9facfac/resourcegroups/resourcegroup-operators/providers/Microsoft.ManagedIdentity/userAssignedIdentities/aso-manager-identity/credentials?tid=72f988bf-86f1-41af-91ab-2d7cd011db47&oid=ddcc0726-c3cd-49b2-9a4b-68a4a33bdc1d&aid=288a7d63-ab78-442e-89ee-2a353fb990ab", - "id": "/subscriptions/7060bca0-7a3c-44bd-b54c-4bb1e9facfac/resourcegroups/resourcegroup-operators/providers/Microsoft.ManagedIdentity/userAssignedIdentities/aso-manager-identity", - "location": "westus", - "name": "aso-manager-identity", - "principalId": "ddcc0726-c3cd-49b2-9a4b-68a4a33bdc1d", - "resourceGroup": "resourcegroup-operators", - "tags": {}, - "tenantId": "72f988bf-86f1-41af-91ab-2d7cd011db47", - "type": "Microsoft.ManagedIdentity/userAssignedIdentities" - } - ``` - -2. Give the Service Principal associated with the AKS cluster control over managing the identity we just created. - - ```shell - az role assignment create --role "Managed Identity Operator" --assignee --scope - - az role assignment create --role "Managed Identity Operator" --assignee --scope "/subscriptions/7060bca0-7a3c-44bd-b54c-4bb1e9facfac/resourcegroups/resourcegroup-operators/providers/Microsoft.ManagedIdentity/userAssignedIdentities/aso-manager-identity" - ``` - -3. Give the Managed Identity we just created authorization to provision resources in our subscription - - ```shell - az role assignment create --role "Contributor" --assignee --scope - - az role assignment create --role "Contributor" --assignee "288a7d63-ab78-442e-89ee-2a353fb990ab" --scope "/subscriptions/7060bca0-7a3c-44bd-b54c-4bb1e9facfac" - ``` - -4. Install [aad-pod-identity](https://github.com/Azure/aad-pod-identity#1-create-the-deployment) - - ```shell - make install-aad-pod-identity - ``` - -5. Create and apply the AzureIdentity and Binding manifests - - ```yaml - apiVersion: "aadpodidentity.k8s.io/v1" - kind: AzureIdentity - metadata: - name: - namespace: azureoperator-system - spec: - type: 0 - resourceID: /subscriptions//resourcegroups//providers/Microsoft.ManagedIdentity/userAssignedIdentities/ - clientID: - ``` - - ```yaml - apiVersion: "aadpodidentity.k8s.io/v1" - kind: AzureIdentityBinding - metadata: - name: aso-identity-binding - namespace: azureoperator-system - spec: - azureIdentity: - selector: aso_manager_binding - ``` diff --git a/docs/apimgmt/apimgmt.md b/docs/services/apimgmt/apimgmt.md similarity index 100% rename from docs/apimgmt/apimgmt.md rename to docs/services/apimgmt/apimgmt.md diff --git a/docs/appinsights/appinsights.md b/docs/services/appinsights/appinsights.md similarity index 100% rename from docs/appinsights/appinsights.md rename to docs/services/appinsights/appinsights.md diff --git a/docs/azuresql/azuresql.md b/docs/services/azuresql/azuresql.md similarity index 100% rename from docs/azuresql/azuresql.md rename to docs/services/azuresql/azuresql.md diff --git a/docs/cosmosdb/cosmosdb.md b/docs/services/cosmosdb/cosmosdb.md similarity index 100% rename from docs/cosmosdb/cosmosdb.md rename to docs/services/cosmosdb/cosmosdb.md diff --git a/docs/eventhub/eventhub.md b/docs/services/eventhub/eventhub.md similarity index 100% rename from docs/eventhub/eventhub.md rename to docs/services/eventhub/eventhub.md diff --git a/docs/keyvault/keyvault.md b/docs/services/keyvault/keyvault.md similarity index 100% rename from docs/keyvault/keyvault.md rename to docs/services/keyvault/keyvault.md diff --git a/docs/mysql/mysql.md b/docs/services/mysql/mysql.md similarity index 100% rename from docs/mysql/mysql.md rename to docs/services/mysql/mysql.md diff --git a/docs/postgresql/postgresql.md b/docs/services/postgresql/postgresql.md similarity index 100% rename from docs/postgresql/postgresql.md rename to docs/services/postgresql/postgresql.md diff --git a/docs/rediscache/rediscache.md b/docs/services/rediscache/rediscache.md similarity index 100% rename from docs/rediscache/rediscache.md rename to docs/services/rediscache/rediscache.md diff --git a/docs/resourcegroup/resourcegroup.md b/docs/services/resourcegroup/resourcegroup.md similarity index 100% rename from docs/resourcegroup/resourcegroup.md rename to docs/services/resourcegroup/resourcegroup.md diff --git a/docs/storage/blobcontainer.md b/docs/services/storage/blobcontainer.md similarity index 100% rename from docs/storage/blobcontainer.md rename to docs/services/storage/blobcontainer.md diff --git a/docs/storage/storageaccount.md b/docs/services/storage/storageaccount.md similarity index 100% rename from docs/storage/storageaccount.md rename to docs/services/storage/storageaccount.md diff --git a/docs/virtualmachine/virtualmachine.md b/docs/services/virtualmachine/virtualmachine.md similarity index 100% rename from docs/virtualmachine/virtualmachine.md rename to docs/services/virtualmachine/virtualmachine.md diff --git a/docs/virtualnetwork/loadbalancer.md b/docs/services/virtualnetwork/loadbalancer.md similarity index 100% rename from docs/virtualnetwork/loadbalancer.md rename to docs/services/virtualnetwork/loadbalancer.md diff --git a/docs/virtualnetwork/networkinterface.md b/docs/services/virtualnetwork/networkinterface.md similarity index 100% rename from docs/virtualnetwork/networkinterface.md rename to docs/services/virtualnetwork/networkinterface.md diff --git a/docs/virtualnetwork/publicipaddress.md b/docs/services/virtualnetwork/publicipaddress.md similarity index 100% rename from docs/virtualnetwork/publicipaddress.md rename to docs/services/virtualnetwork/publicipaddress.md diff --git a/docs/virtualnetwork/virtualnetwork.md b/docs/services/virtualnetwork/virtualnetwork.md similarity index 100% rename from docs/virtualnetwork/virtualnetwork.md rename to docs/services/virtualnetwork/virtualnetwork.md diff --git a/docs/vmscaleset/vmscaleset.md b/docs/services/vmscaleset/vmscaleset.md similarity index 100% rename from docs/vmscaleset/vmscaleset.md rename to docs/services/vmscaleset/vmscaleset.md diff --git a/docs/test.md b/docs/test.md deleted file mode 100644 index 0dd280c6990..00000000000 --- a/docs/test.md +++ /dev/null @@ -1,10 +0,0 @@ -# Testing - -Testing the full project can be done in two ways: - -- `make api-test` - Runs the Kubernetes API tests against the CRDs -- `make test` - Test against the Kubernetes integration testing framework. -- `make test-existing-managers` - Test the resource managers against an existing cluster. This is currently the easiest way to run tests against a kind cluster setup. -- `make test-existing-controllers` - Test the controllers against an existing cluster. - -Some test suites (primarily the controller suite) have included Go Build Tags to allow selectively running tests. Users can specify individual test suites by setting the `BUILD_TAGS` parameter as an environment variable or before the make target: `make BUILD_TAGS=azuresqlservercombined test-existing-controllers`. Test files declare their tags in the `// +build` comment at the top of the file. diff --git a/docs/kubebuilder.md b/docs/topics/kubebuilder.md similarity index 96% rename from docs/kubebuilder.md rename to docs/topics/kubebuilder.md index 00cc0fc1786..aef4b157fa6 100644 --- a/docs/kubebuilder.md +++ b/docs/topics/kubebuilder.md @@ -1,4 +1,4 @@ -# Tips for issues you may encounter with Kubebuilder +# Tips & tricks for Kubebuilder 1. Kubebuilder documentation recommends you to install Kubebuilder using the following commands. diff --git a/docs/customresource.md b/docs/topics/resourceprovision.md similarity index 93% rename from docs/customresource.md rename to docs/topics/resourceprovision.md index b0a36b32f1c..03b6276cf68 100644 --- a/docs/customresource.md +++ b/docs/topics/resourceprovision.md @@ -2,15 +2,13 @@ ## Deploy Custom Resource -You can follow the steps [here](/docs/development.md) to run the operator locally or follow the steps [here](/docs/deploy.md) to deploy to a real Kubernetes cluster. - -You can use the YAML files in the `config/samples` folder to create the resources using the following command. +Once the Azure Service Operator is deployed, you can use the YAML files in the `config/samples` folder to create the resources using the following command. ``` kubectl apply -f ``` -### Tags in Azure +## Tags in Azure When deploying resources using the YAML files, you can specify as labels any tags you want to add to the resource in Azure. If the labels contain characters that are not allowed as tags in Azure (<,>,\,/,%,?), those characters will be replaced by a period(.) and added as Azure tags. diff --git a/docs/secrets.md b/docs/topics/secrets.md similarity index 97% rename from docs/secrets.md rename to docs/topics/secrets.md index 335c9c56012..765953afceb 100644 --- a/docs/secrets.md +++ b/docs/topics/secrets.md @@ -1,4 +1,4 @@ -# Access information of Resource post deployment +# Information about the Resource post deployment Many of the Azure resources have access information like connection strings, access keys, admin user password etc. that is required by applications consuming the resource. This information is stored as secrets after resource creation.