diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 457be85535..c1f6d9462f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,10 +2,28 @@ Radius is in an early phase of development right now. We welcome feedback in the form of issues that comes from usage and is aligned with the current scope and goals of the project. -We welcome small PR contributions from outside the core team (docs improments, bug fixes, minor features.) as long as they follow a few guidelines: +## Table of contents -- Please start by [opening an issue](https://github.com/project-radius/radius/issues/new/choose) unless is it truly minor (ex: correcting a typo) -- Please work with the [core team](mailto:radiusct@microsoft.com) to ensure that what you're doing is in scope for the project before writing any code +You can find our full **contributor documentation** including instructions at the following links: + +- [How to contribute](./docs/contributing/how-to.md) +- [See "good first issues"](https://github.com/project-radius/radius/issues?q=is:issue+is:open+label:%22good+first+issue%22) +- [Install prerequisites](./docs/contributing/contributing-code/contributing-code-prerequisites/) +- [Create your first commit (full walkthrough)](./contributing-code-first-commit/first-commit-00-prerequisites.md) +- [Building the repo](./docs/contributing/contributing-code/contributing-code-building/) +- [Understanding repo organiztion](./docs/contributing/contributing-code/contributing-code-organization/) +- [Contribute to issues](./docs/contributing/contributing-issues/) +- [Create pull requests](./docs/contributing/contributing-pull-requests/) +- [Contribute to documentation](https://github.com/project-radius/docs) + +## Current status + +We welcome small pull request contributions from anyone (docs improments, bug fixes, minor features.) as long as they follow a few guidelines: + +- For very minor changes like correcting a typo feel free to send a pull request. Otherwise ... +- Please start by [choosing an existing issue](https://github.com/project-radius/radius/issues), or [opening an issue](https://github.com/project-radius/radius/issues/new/choose) to work on. +- The maintainers will respond to your issue, please work with the maintainers to ensure that what you're doing is in scope for the project before writing any code. +- If you have any doubt whether a contribution would be valuable, feel free to ask. ## Code of conduct diff --git a/Makefile b/Makefile index 865bf8ca1d..36968036aa 100644 --- a/Makefile +++ b/Makefile @@ -17,4 +17,4 @@ ARROW := \033[34;1m=>\033[0m # order matters for these -include build/help.mk build/version.mk build/build.mk build/util.mk build/generate.mk build/test.mk build/controller.mk build/docker.mk build/recipes.mk build/install.mk build/debug.mk +include build/help.mk build/version.mk build/build.mk build/util.mk build/generate.mk build/test.mk build/docker.mk build/recipes.mk build/install.mk build/debug.mk diff --git a/build/check-kcp.sh b/build/check-kcp.sh deleted file mode 100755 index e12d758886..0000000000 --- a/build/check-kcp.sh +++ /dev/null @@ -1,13 +0,0 @@ -#! /bin/bash -set -u - -ps | grep kcp | grep -v grep -if [[ ! $? -eq 0 ]]; then - echo 'kcp must be started before running radiusd-run target ("~/.rad/bin/kcp start")' - exit 1 -fi - -if [[ ! -e ~/.rad/bin/.kcp/data/admin.kubeconfig ]]; then - echo 'kcp cubeconfig file not found (expected "~/.rad/bin/.kcp/data/admin.kubeconfig" to exist' - exit 2 -fi diff --git a/build/controller.mk b/build/controller.mk deleted file mode 100644 index def832b3b5..0000000000 --- a/build/controller.mk +++ /dev/null @@ -1,24 +0,0 @@ -# ------------------------------------------------------------ -# Copyright 2023 The Radius Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ------------------------------------------------------------ -##@ Controller - -kubernetes-deploy: docker-build-radius-rp docker-push-radius-rp controller-deploy-existing ## Deploy controller to the K8s cluster specified in ~/.kube/config. - -kubernetes-deploy-existing: generate-k8s-manifests ## Deploy controller to the K8s cluster specified in ~/.kube/config. - go run ./cmd/rad/main.go install kubernetes --reinstall --chart deploy/Chart/ --image $(DOCKER_REGISTRY)/radius-rp --tag $(DOCKER_TAG_VERSION) - -kubernetes-undeploy: ## Uninstall controller from the K8s cluster specified in ~/.kube/config. - go run ./cmd/rad/main.go uninstall kubernetes diff --git a/build/install.mk b/build/install.mk index a749dec81e..c239720a63 100644 --- a/build/install.mk +++ b/build/install.mk @@ -20,9 +20,5 @@ RAD_LOCATION := /usr/local/bin/rad .PHONY: install install: build-binaries ## Installs a local build for development - @echo "$(ARROW) Installing rad" - cp $(OUT_DIR)/$(GOOS)_$(GOARCH)/$(BUILDTYPE_DIR)/rad$(BINARY_EXT) $(RAD_LOCATION) - - @echo "$(ARROW) Displaying output" - tree $(HOME)/.rad -a \ No newline at end of file + cp $(OUT_DIR)/$(GOOS)_$(GOARCH)/$(BUILDTYPE_DIR)/rad$(BINARY_EXT) $(RAD_LOCATION) \ No newline at end of file diff --git a/deploy/Chart/charts/rp/templates/deployment.yaml b/deploy/Chart/charts/rp/templates/deployment.yaml index c33a2db644..81c878b6e7 100644 --- a/deploy/Chart/charts/rp/templates/deployment.yaml +++ b/deploy/Chart/charts/rp/templates/deployment.yaml @@ -39,8 +39,6 @@ spec: value: 'self-hosted' - name: K8S_CLUSTER value: 'true' - - name: SKIP_AUTH - value: 'true' {{ if .Values.publicEndpointOverride}} - name: RADIUS_PUBLIC_ENDPOINT_OVERRIDE value: {{ .Values.publicEndpointOverride }} diff --git a/docs/README.md b/docs/README.md index c2c760d7e5..e0b53fe3c9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,7 +1,9 @@ # Project Radius documentation -The docs for Project Radius are at https://radapp.dev, with the source in the [project-radius/docs repo](https://github.com/project-radius/docs). +The documentation for Project Radius is at https://radapp.dev, with the source in the [project-radius/docs repo](https://github.com/project-radius/docs). ## Contributing to Project Radius -To contribute to Project Radius, refer to the [contributing docs](./contributing/). +This folder contains the documentation for contributing to Radius. + +To browse the table of contents, refer to the [contributing docs](./../CONTRIBUTING.md). diff --git a/docs/adr/000-adr-template.md b/docs/adr/000-adr-template.md deleted file mode 100644 index 0e17396beb..0000000000 --- a/docs/adr/000-adr-template.md +++ /dev/null @@ -1,23 +0,0 @@ - -# 000 ADR: This is the title - -## Stakeholders - - -## Status - -proposed - - - -## Context - - -## Decision - - - -## Consequences - - \ No newline at end of file diff --git a/docs/adr/001-adr-adopt-adrs.md b/docs/adr/001-adr-adopt-adrs.md deleted file mode 100644 index d28077291a..0000000000 --- a/docs/adr/001-adr-adopt-adrs.md +++ /dev/null @@ -1,51 +0,0 @@ -# 001 ADR: Adopt Architectural Decision Records (ADRs) - -## Stakeholders - -* Radius Core Team - -## Status - -accepted - -## Context - -An architecture decision record is a short text file in a format. Each record describes a set of considerations that led to a significant decision in the process of creating a software system, the decisions made and the consequences of those decisions. - -ADRs were initially proposed by Michael Nygard in his article ["Documenting Architecture Decisions"](https://www.cognitect.com/blog/2011/11/15/documenting-architecture-decisions), in the article the proposed format and a description of each one of the sections that compose it is detailed. - -The ADR document aims to contain just enough information to help individuals onboarding or reviewing the project to understand how the team arrived at the current solution and what were the driving forces that shaped this current state. - -Notably, Michael Nygard mentions: - ->The whole document should be one or two pages long using the same layout this document follows. We will write each ADR as if it is a conversation with a future developer. This requires good writing style, with full sentences organized into paragraphs. Bullets are acceptable only for visual style, not as an excuse for writing sentence fragments. -(Bullets kill people, even PowerPoint bullets.) - -To ease the process of creation of ADRs we recommend the usage of the console application [adr-tools](https://github.com/npryce/adr-tools), however its use is not required to create ADRs. - -### When should I write an ADR? - -Joseph Blake, a Spotify engineer published: [When Should I Write an Architecture Decision Record](https://engineering.atspotify.com/2020/04/when-should-i-write-an-architecture-decision-record/) with an easy to follow instructions helping us to decide if an ADR should be written to record a decision. - -The process is summarized nicely in the following diagram: -![adr-diagram](https://engineering.atspotify.com/wp-content/uploads/sites/2/2020/04/6b4d58b6-architecture-decision-record_diagram.png) - -## Decision - -We will adopt the use of ADRs to record "architecturally significant" decisions. -ADRs will be review as Pull Requests to our repository and kept as Markdown files in the docs/adr directory. The ADRs will follow the format proposed by Michael Nygard and documented as a template adr in [`adr-0-template.md`](adr-0-template.md) - -The following process will be used to approve ADRs: - - 1. The author will use the decision diagram (described above) to decide if an ADR should be added with their code submission. - 1. The author will submitted the ADR and create a pull request to this repository alongside the implementation (when applicable) - 1. The author will identify the people required to accept the decision request their review using the standard GitHub process. - 1. If an ADR is meant to supersede a previously approved ADR, the author will make a change on the superseded documents as part of their ADR pull request submission. - -## Consequences - -* Future team members are able to read a history of decisions and quickly get up to speed on how and why a decision is made, and the impact of that decision -* ADRs enable our teams to align on best practices across our project and will enhance the consistency and cohesion of our codebase -* The process of discussing "architecturally significant" decisions will be more inclusive to team members and enable relevant people to offer their thoughts and opinions in an asynchronous way -* Using ADRs will require authors to make a significant time investment articulating clearly the decisions being made and the alternatives considered. -* It will take some time to familiarize and adopt correctly ADRs and some churn should be expected as the team refines the process and accommodates to the new paradigm diff --git a/docs/adr/003-shared-data-store.md b/docs/adr/003-shared-data-store.md deleted file mode 100644 index 2cd263133c..0000000000 --- a/docs/adr/003-shared-data-store.md +++ /dev/null @@ -1,19 +0,0 @@ -# 003 ADR: Shared Data Store for Radius RP and UCP - -## Stakeholders - -* Radius Core Team - -## Status - -accepted - -## Context - -Right now, the Radius RP and UCP require a shared data store. This ADR documents the need for a shared data store between the Radius RP and UCP. This is subject to change in the future. - -UCP owns the ResourceGroup resource and implements the CRUD operations on the ResourceGroup. All the Applications.Core/Applications.Link Resource Provider resources are contained within the resource group but are owned by the RP. - -We need to enable querying of all resources within a resource group for supporting deletion of a resourceGroup. However, since the individual resources within the resource group are owned by the RP, the UCP has no knowledge of those unless we have a shared data store. - -With a shared data store, UCP can make a query to the data store to return all resources starting with the prefix "/resourceGroups/" and retrieve a list of all resources under the resource group. UCP can then make individual delete requests on each resource which will be processed by the RP. \ No newline at end of file diff --git a/docs/adr/README.md b/docs/adr/README.md deleted file mode 100644 index a001e5d57c..0000000000 --- a/docs/adr/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# Architecture Design Records - -This directory is where we store our Architecture Design Records (ADRs). If you're new to the team or would like to better understand the decision to use ADRs take a look at our first ADR [`000-adr-template.md`](000-adr-template.md) to build the necessary context. - -## Directory Structure - -We use the following directory structure: - -* Use a folder per component -* Use a three digit prefix for easy file browsing - -For example, -``` -/docs/adr/ucp -/docs/adr/bicep-extensibility -/docs/adr/cli -... -```` - -File-naming -``` -000-ucp-.md -``` - -## When should I write an ADR? - -Joseph Blake, a Spotify engineer published: [When Should I Write an Architecture Decision Record](https://engineering.atspotify.com/2020/04/when-should-i-write-an-architecture-decision-record/) with an easy to follow instructions helping us to decide if an ADR should be written to record a decision. - -The process is summarized nicely in the following diagram: -![adr-diagram](https://engineering.atspotify.com/wp-content/uploads/sites/2/2020/04/6b4d58b6-architecture-decision-record_diagram.png) \ No newline at end of file diff --git a/docs/adr/bicep-extensibility/001-bicep-extensibility-types.md b/docs/adr/bicep-extensibility/001-bicep-extensibility-types.md deleted file mode 100644 index 45806c7ecd..0000000000 --- a/docs/adr/bicep-extensibility/001-bicep-extensibility-types.md +++ /dev/null @@ -1,46 +0,0 @@ -# 001 ADR: Bicep Extensibility Types for Radius - -## Stakeholders - -* Radius Core Team - -## Status - -accepted - -## Context - -[Bicep Extensibility](https://github.com/Azure/bicep/issues/3565) is a feature delivered by the ARM team which allows for resource to be deployed outside of the ARM control plane. We would like to adopt bicep extensibility for radius types to integrate in a more modular way with the Bicep project and reduce the need to keep a separate Bicep fork. - -The extensibility features in Bicep at the time of writing are in the very early design and implementation steps, the initial design is discussed in [the Bicep extensibility proposal](https://github.com/Azure/bicep/issues/3565). This design calls out two separate points of integration of extensibility types into the Bicep project: (1) Client-Side and (2) Server-Side (the linked proposal describes in them in detail). - -The initial exploration of the Client-Side integration revealed that the mechanism used by Bicep to load extensibility type definitions is to statically link a dll that loads them. Current extensibility loader implementations (for Az types and Kubernetes types) implement the [`ITypeLoader`](https://github.com/project-radius/bicep/tree/bicep-extensibility/src/Bicep.Types.Radius) interface and are published as a dll in a NuGet package that in turn is consumed by the Bicep project (see here for the [exact code reference](https://github.com/project-radius/bicep/blob/f2e9572e7a0647bc13710f36cc7d6ef6da45dd48/src/Bicep.Core/Bicep.Core.csproj#L36-L38)) - -In addition to the dll, other code changes are necessary on the Bicep solution before the types become available as listed below: - -* The `BICEP_IMPORTS_ENABLED_EXPERIMENTAL` and `BICEP_SYMBOLIC_NAME_CODEGEN_EXPERIMENTAL` flags must be set in the process running Bicep (language server and cli) -* The following additions must be made to `Bicep.Core` project: - * Author and connect a C# class (see here for a [concrete example](https://github.com/project-radius/bicep/blob/bicep-extensibility/src/Bicep.Core/Semantics/Namespaces/RadiusNamespaceType.cs)) that implements the `INamespaceProvider` interface in the `Bicep.Core.Semantics.Namespaces` namespace. - * Author and connect a C# class (see here for a [concrete example](https://github.com/project-radius/bicep/blob/bicep-extensibility/src/Bicep.Core/TypeSystem/Radius/RadiusResourceTypeProvider.cs)) that implements the `IResourceTypeProvider` interface to load the definitions from the statically linked dll. - -Iteration on the extensibility types definition separate from the Bicep release process is not possible until the coupling issues described above are addressed. We will continue to need a Bicep fork until that time. - -In summary, the following blocker items must be addressed before we are able to fully adopt Bicep extensibility types: - -* The mechanism by which extensibility types are loaded to the Bicep binaries changes to be loaded dynamically vs a statically reference -* No code additions are needed in the Bicep solution to load Bicep extensibility type definitions - -## Decision - -* We will maintain a Bicep fork with the necessary plumbing to support Radius types -* We will implement guardrails to ensure generated types are kept up to date whenever a change in the specification is committed to the codebase -* We will automate the process of publishing the Bicep bits so that they are accessible in both production and developer iterations - -## Consequences - -* We will maintain a copy of the type generator source in the Radius repository until the type generator is released and supported separately by the Bicep team. This code lives under `/hack/**` -* We will create and use the [`bicep-extensibility`](https://github.com/project-radius/bicep/tree/bicep-extensibility) branch to contain the code necessary to support Radius types as extensibility types in Bicep -* Whenever the type definitions for the resource provider are updated, the following must take place: - 1. Generate a set of markdown and json files that describe the type definitions in the Bicep internal serialization format (`make generate`) - 1. Verify the changes had the desired effect by inspecting the artifacts in the [project-radius/bicep](https://github.com/project-radius/bicep/tree/bicep-extensibility) repo under branch `bicep-extensibility` provide the desired functionality - 1. Merge the automatically generated PR, this will result with the generated Bicep bits to be published in the [radius blob storage](https://radiuspublic.blob.core.windows.net) diff --git a/docs/adr/bicep-extensibility/002-bicep-ext-local-environments-deploy-azure-resources.md b/docs/adr/bicep-extensibility/002-bicep-ext-local-environments-deploy-azure-resources.md deleted file mode 100644 index 4db8f6ba15..0000000000 --- a/docs/adr/bicep-extensibility/002-bicep-ext-local-environments-deploy-azure-resources.md +++ /dev/null @@ -1,45 +0,0 @@ -# 002 ADR: Enable local environments to deploy Azure resources - -## Stakeholders - -* Radius Core Team - -## Status - -accepted - -## Context - -Credentials are necessary to be able to deploy Azure resources, at the time of writing a user that creates a new standalone Radius environment (dev, kubernetes) cannot specify what credentials should be used for deploying Azure resources. - -We want users to be able to deploy Azure resources to 'dev' and 'kubernetes' Radius environments. The following options are explored to specify the required credentials: - -### Proposed Solution: User creates a service principal name to be used for deployment of Azure resource types - -In this flow, the user creates and configures a service principal name (SPN) with the corresponding role bindings before initializing a Radius standalone environment ('dev' or 'kubernetes'). During environment creation (`rad env init`), the user provides the `client_id`, `client_secret` and `tenant_id` of the managed identity that will be used by the deployment engine when making ARM requests. - -For example, the user could use the command [`az ad sp create-for-rbac`](https://docs.microsoft.com/en-us/cli/azure/ad/sp?view=azure-cli-latest#az-ad-sp-create-for-rbac) to create the SPN - -![diagram_user_creates_spn](../../uml/enable-local-environments-to-deploy-azure-resources/fig-1-user-creates-spn.png) - -The identifier of the managed identity will be stored as a secret in the runtime environment and will be appended to the runtime context of the deployment engine -The deployment engine will load the credentials from environment variables set in its runtime. - -![diagram_user_creates_radius_env](../../uml/enable-local-environments-to-deploy-azure-resources/fig-2-radius-environment.png) - -### Interactive flow - - - -## Decision - -* We will adopt the proposed solution described above - -## Consequences - -* The user will need to create a SPN with the appropriate role bindings to be able to deploy Azure resources which adds complexity to the 'dev' environment setup -* Standalone (kubernetes) with SPN will be the recommended experience for shared standalone production deployments -* We will research for a more convenient way to create Azure resources in the 'dev' environments that doesn't require a SPN to simplify the local developer experience -* We will use the naming convention used in the result of calling `az ad sp create-for-rbac` (`appId`, `password` and `tenant`) in the interactive flow to create a Radius environment -* We will use the canonical terminology (`client_id`, `client_secret` and `tenant_id`) for non-interactive invocations of the Radius CLI - diff --git a/docs/adr/ucp/001-aws-resource-updating.md b/docs/adr/ucp/001-aws-resource-updating.md deleted file mode 100644 index cd13859a2c..0000000000 --- a/docs/adr/ucp/001-aws-resource-updating.md +++ /dev/null @@ -1,199 +0,0 @@ -# 001 ADR: Update strategy for AWS resources - -## Stakeholders - -Radius Core Team - -## Status - -proposed - -## Context - -Radius (UCP) updates AWS Resources using the [AWS CloudControl update-resource API](https://docs.aws.amazon.com/cloudcontrolapi/latest/userguide/resource-operations-update.html). This API expects a [JSON Patch](https://jsonpatch.com/) document to know what updates to make to the resource. - -Each resource type in AWS has a schema, which lists its properties and describes which properties on the resource are read-only, write-only, create-only, and so on. - -### Example: AWS MemoryDB -Here is a snippet of the resource type schema of an AWS MemoryDB resource. -```json -{ - "definitions": { - "Endpoint": { - "type": "object", - "additionalProperties": false, - "properties": { - "Address": { - "description": "The DNS address of the primary read-write node.", - "type": "string" - }, - "Port": { - "description": "The port number that the engine is listening on. ", - "type": "integer" - } - } - }, - }, - "properties": { - "ClusterName": { - "description": "The name of the cluster. This value must be unique as it also serves as the cluster identifier.", - "pattern": "[a-z][a-z0-9\\-]*", - "type": "string" - }, - "ARN": { - "description": "The Amazon Resource Name (ARN) of the cluster.", - "type": "string" - }, - "ClusterEndpoint": { - "description": "The cluster endpoint.", - "$ref": "#/definitions/Endpoint" - }, - "NumShards": { - "description": "The number of shards the cluster will contain.", - "type": "integer" - }, - }, - "readOnlyProperties": [ - "/properties/ClusterEndpoint/Address", - "/properties/ClusterEndpoint/Port", - "/properties/ARN", - ], - "createOnlyProperties": [ - "/properties/ClusterName", - ], -} -``` - -Note that AWS properties can be nested (such as `/properties/ClusterEndpoint/Address`). Since there are nested properties in AWS resource type schemas, there needs to be special handling for them to ensure that the generated patch sent to `update-resource` is correct. - -### Property Types - -[Reference](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/resource-type-schema.html) - -There are different types of properties that can exist on an AWS resource type: - -#### readOnlyProperties -_Resource properties that can be returned by a read or list request, but can't be set by the user._ - -#### writeOnlyProperties -_Resource properties that can be specified by the user, but can't be returned by a read or list request._ - -#### conditionalCreateOnlyProperties -_A list of JSON pointers for properties that can only be updated under certain conditions. For example, you can upgrade the engine version of an RDS DBInstance but you cannot downgrade it. When updating this property for a resource in a CloudFormation stack, the resource will be replaced if it cannot be updated._ - -If a `conditionalCreateOnlyProperty` is specified and fulfills the condition to be updatable, then it will successfully be updated. Otherwise, it will throw an error to the user. e.g.: - -``` -"code": "ResourceConflict", -"message": "VPC Multi-AZ DB Instances are not available for engine: sqlserver-ex (Service: Rds, Status Code: 400, Request ID: c6f2ad6b-29cc-4024-bbe5-7ce3e8a4b5ad)" -``` - -#### nonPublicProperties -_A list of JSON pointers for properties that are hidden. These properties will still be used but will not be visible._ - -#### createOnlyProperties -_Resource properties that can be specified by the user only during resource creation._ - -#### deprecatedProperties -_Resource properties that have been deprecated by the underlying service provider. These properties are still accepted in create and update operations. However they may be ignored, or converted to a consistent model on application. Deprecated properties are not guaranteed to be returned by read operations._ - - -### How CloudControl updates resources - -[Reference](https://docs.aws.amazon.com/cloudcontrolapi/latest/userguide/resource-operations-update.html#resource-operations-update-patch) - -The update request to CloudControl executes in two steps: - -1. CloudControl will sequentially apply the operations in the patch document, using the output of the previous operation as the input of the next. Note that this process will not result in any actual changes to the resource in AWS yet. If an error occurs during (for example, specifying a `readOnlyProperty`, CloudControl will stop the patching and report the error back. - -2. If validation from each of the patch operations succeeds, then CloudControl will update the resource to the DesiredState specified by the patch document. - -This means that update requests via CloudControl will occur in an idempotent way. Any invalid properties sent to CloudControl will not result in the resource being edited. - - -## Decision - -### Strategy - -The strategy for handling these updates with nested resources is the following: - -1. Retrieve the desired state of the resource (from user-specified bicep manifest) -1. Retrieve the current state of the resource (from CloudControl `get-resource` API) -1. Retrieve the resource type schema of the resource (from CloudFormation `describe-type` API) -1. "Flatten" the current and desired states (details below) -1. Add read-only and create-only properties from the current state to the desired state -1. "Unflatten" the current and desired states (details below) -1. Compare the current state and the updated desired state to produce the patch document - -### Flatten/Unflatten - -#### Flatten - -Flatten takes an object that may have nested properties and converts it to an object with only top-level properties. - -```go -in := map[string]interface{}{ - "NumShards": 1, - "ClusterEndpoint": map[string]interface{}{ - "Address": "test-address", - "Port": 3000, - }, -} - -out := Flatten(in) -// out = map[string]interface{}{ -// "NumShards": 1, -// "ClusterEndpoint/Address": "test-address", -// "ClusterEndpoint/Port": 3000, -// } -``` - -#### Unflatten - -Unflatten takes an object with top-level properties (specified in paths, such as `ClusterEndpoint/Address`) and converts it to an object that can have nested properties. - -```go -in := map[string]interface{}{ - "NumShards": 1, - "ClusterEndpoint/Address": "test-address", - "ClusterEndpoint/Port": 3000, -} - -out := Unflatten(in) -// out = map[string]interface{}{ -// "NumShards": 1, -// "ClusterEndpoint": map[string]interface{}{ -// "Address": "test-address", -// "Port": 3000, -// }, -// } -``` - -### Property Handling - -#### Create-Only Properties -Create-only properties from the current state are added (if not present) to the desired state so that when the desired state is compared to the current state, no patch is generated. - -#### Read-Only Properties -Read-only properties from the current state are added (if not present) to the desired state so that when the desired state is compared to the current state, no patch is generated. - -#### Conditional Create-Only Properties -We will intentionally not do any validation on conditional create-only properties because the value may be valid as an update. If it is invalid, CloudControl will send back an error to the user and perform no updates to the resource. - -#### Write-Only Properties -Write-only properties are never returned as part of the GetResource response. This means that we cannot create a diff against write-only properties. - - -## Consequences - -### Update logic can now handle nested properties -Flattening the current and desired states allows for each of the special property types to be considered during the comparison. For example, since the `ClusterEndpoint` property itself is not read-only and all of its sub-properties (`Address`, `Port`) are, the user would not be allowed to provide `ClusterEndpoint` in their desired state for a MemoryDB resource. Without performing special handling (i.e. just determining the patch from the top-level fields), an invalid patch would be generated. - -### Update logic is more complicated -Introducing the flatten/unflatten code makes the update code more complicated and prone to bugs. Extra unit tests must also be run to validate that this behavior works correctly. - -### Create-And-Write-Only properties cannot be updated -Since write-only properties cannot come back as a response from AWS, they cannot be compared to the user's desired state. Therefore, on update requests, we ignore create-and-write-only properties. This means that a user could create a resource, update a create-and-write-only property, try to update the resource, and see that this property update is not reflected in the resource state. - -### Array properties will currently be unsupported -Some properties can be specified under an array entry. For example, `/properties/DefaultActions/*/TargetGroupArn` under the AWS::ElasticLoadBalancingV2::Listener resource. This behavior will currently be unsupported by this design. diff --git a/docs/contributing/README.md b/docs/contributing/README.md deleted file mode 100644 index 82dc7506f3..0000000000 --- a/docs/contributing/README.md +++ /dev/null @@ -1,501 +0,0 @@ -# Contributing to Project Radius - -## Architecture - -Project Radius can be best understood as the combination of the following components: - -- The **`rad` CLI** for deploying and managing environments and applications -- The **application model** for describing applications as a set of components, groupings, and relationships -- The **Bicep** language and tools which includes the application model as a set of types -- The **ARM Deployment Engine** which process the output of the Bicep compiler -- The **Radius API** which interfaces with the ARM deployment engine and other actors to handle individual operations on the application model -- The **Radius Control Plane** that implements operations on the application model as a sequence of resource management operations on a hosting platform -- The **Hosting Platform** that provides the underlying capabilies used by the application model such as running containers and databases - -The remainder of this document will explain these components and processes in detail. The intention is to provide enough detail to be useful to new contributors to the project as well as understanding for curious users that want to know about the inner workings of the system. As such, it is recommended that you read and understand the application model concepts before diving into architecture. - -## Callouts - -As Project Radius is still being developed, some of the information here is speculative, incomplete, or otherwise reflective of the *future state* of the project. - -Here are some examples of how this kind of information will be emphasized. - -> 🚀 Future State 🚀
-A description of how things will work in the future. - -> 🚧 Under Construction 🚧
-A description of a gap or limitation that we currently have. - ->❓ Open Question ❓
-A description of something we don't quite know yet. - -## Current state - -As an overview, here are some important details about the current state of Radius. At the time of writing we've finished the 0.1 release. - -The 0.1 release is suitable for deploying our limited set of tutorial content on Azure. This document will refer to our current experience and architecture on Azure as the **user-mode PaaS**. **PaaS** because it offers a *platform-as-a-service* developer experience. **user-mode** because the resources needed to run Radius use publicly available extensibility and are created in the users' subscription. We do not manage anything centrally for users in 0.1. - -We have the goal to target and support multiple *hosting platforms* in the future: - -- Azure + AKS: this is the current state for Azure, we target Azure managed services and AKS for compute -- Azure + Serverless: this is the *future state* for Azure, we target Azure managed services and a TBD system for compute -- Kubernetes: will build this soon, no cloud provider required, just Kubernetes -- Local Dev: will build this after Kubernetes, using your dev box and likely Docker as a hosting platform - -## Current status - -- The only supported **hosting platform** is Azure, using a combination of Azure managed services and AKS to deploy applications - - As we have not yet implemented a managed service, infrastructure like the AKS cluster running compute workloads is part of the users' subscription -- The **Radius control plane** is very primitive, and requires hand-coded support for every resource type we interact with - - As we have not yet implemented a managed service, the control plane and its resources is part of the users' subscription -- The **Radius API** is only available in the form of an Azure Custom Resource Provider -- We require a custom build of **Bicep** which includes our types and some custom compiler support -- The **application model** has support for a very limited set of components and traits, we have not yet implemented support for scopes or for multiple deployment units within a single application -- The **rad** CLI can be used to create an Azure environment, which deploys all of the resources necessary for the hosting platform and control plane -- The **rad** CLI can be used to manage applications using ARM as the protocol by communicating with the Radius API -- The **rad** CLI can be used to perform diagnostic operations on applications by communicating with the AKS cluster - -![Radius Architecture](architecture.png) - -## rad CLI - -The `rad` CLI provides features in three major areas: - -- Environment setup and management -- Application deployment and management (includes CRUD operations on Radius concepts) -- Application diagnostics and troubleshooting - -It can be hard to draw a clear line between *management* and *troubleshooting*, but I think the distinction is useful even through it is sometimes ambiguous. In general the CLI needs to interact both the management plane of the hosting platform (ARM in Azure) as well as the data plane of the hosting platform (logs, port-forwards). - -> 🚀 Future State 🚀
-We currently implement all functionality in the CLI as a monolith (Kubernetes, Azure, etc.). In the future we may choose to adopt a decentralized plugin model to factor out extensions for cloud providers such as Azure and other proprietary tech. - -### Environment setup - -Environment setup is the process of binding an entry in a local config file to a context where applications can be deployed - and *optionally* performing some setup in that environment. - -An environment can be: - -- A resource group in Azure -- A namespace in Kubernetes -- A user's local Docker daemon - -Conceptually, any hosting platform that Radius could target in the future is an environment. We track the context needed to connect to the hosting platform in the per-user configuration so that the user can easily swap between environments. - -#### Azure - -> 🚧 Under Construction 🚧
-Currently we only support Azure cloud as an environment. - -Azure environments have some notable limitations for now to work as a **user-mode PaaS**. - -- Each resource group where the user wants to deploy Radius applications must have our hosting platform and control-plane running in them. This is performed by our environment setup. -- We support a very limited set of Azure regions based on the availability of resources we use. - -Our environment setup is driven by an ARM template and a deployment script (used to initialize AKS). These operations are part of `rad env init azure`. This is needed today because each environment is self-contained (single-tenant) and does not share resources with other subscriptions or other environments in the same subscription. - -> 🚀 Future State 🚀
-When we have built a fully-managed Azure service it will remove the need for environment setup to create resources in Azure. It will simply add configuration locally. The control-plane and hosting platform will be centrally-managed as multitenant services like other production Azure services. - -A managed service will include the full suite of integrations that users expect. - -- `az` CLI -- Azure Portal -- Azure SDKs - ->❓ Open Question ❓
-There is an open question here about the branding of Radius in Azure in our future state as well as the level of consistency to aim for with other Azure tools like `az` CLI. - -Due to the open-source nature and goals of Radius we blur the lines between a 1st party offering and 3rd party offering. - -Management operations use the ARM protocol to communicate with the Radius API as an Azure resource provider. We have authored an OpenAPI spec for the Radius API and used autorest to generate client code to drive our CLI experiences. We rely on the `az` CLI for authentication and expect users to have it installed for interations with Azure. - -Troubleshooting operations use ARM to retrieve credentials for the environment's AKS cluster and then communicate with it directly using the Kubernetes client libraries. - -> 🚀 Future State 🚀
-In the future it's likely that we'll need to talk to some other data plane for troubleshooting in addition to AKS/Kubernetes. - -#### Kubernetes - -> 🚀 Future State 🚀
-Environment setup for Kubernetes will install required infrastructure via Helm charts to perform required setup on the cluster. Each cluster will need a one-time setup operation to install all of the Radius control-plane components. For example, we might install the Radius API (`radius-operator`) and Deployment Engine to the `radius-system` namespace. - -Once Radius has been installed for the cluster, users then become free to treat each namespace as an environment. Each application must be defined in a single namespace including both the Radius resources (`Application`, `Component`) as well as the supporting output resources (Kubernetes types like `Deployment` and `Service`). Users are free to use namespaces as an organization and RBAC tool - multiple applications per-namespace are allowed. - -On the implementation side, we can use much of `kubectl`s functionality as libraries to enable interop with Kubernetes, for example we can use the full suite of `kubectl`s authentication libraries. Management operations and troubleshooting operations will use the Kubernetes client libraries to interact with Radius concepts and the Kubernetes data plane. - -### Application Model & Bicep - -The application model represents a set of core concepts for deploying and managing cloud-native applications. The application model has extensive coverage via its own [conceptual documentation](https://edge.radapp.dev/concepts/appmodel-concept/). This section will focus on the technical details of the representation. - -We use Bicep because it's an expressive and productive language for describing infrastructure and deployments. Using Bicep for Azure allows a transparent abstraction over the rest of Azure - Radius can reference ARM types and vice-versa. In the future the same will be possible for Kubernetes, Bicep will support seamless interop between Kubernetes types and Radius types. - -The application model is represented in Bicep as a set of ARM-like types. They are ARM-like because they don't follow ARM's conventions around naming of naming. - -For example: - -```sh -resource app 'radius.dev/Application@v1alpha3' = { - ... -} -``` - -An ARM type would have a name/version like `Microsoft.Radius/application@2020-01-01`. - -> 🚀 Future State 🚀
-We make sure of several ARM-isms today but it's likely we'll gain further distance as we embrace Kubernetes more. - -For example our objects allow users to set all of the top-level ARM resource properties, and additionally wrap all of our data in a `properties` node. We'll remove this in the future to simplify the authoring experience and ensure that we're neither coupled to ARM or Kubernetes. - -When we create a production resource provider as part of a service, it will likely reflect the Microsoft-branded nature of such a service (`Microsoft.Radius/application@2020-01-01`). Similarly in Kubernetes, our resources will be represented as CRDs that follow all of the related conventions. - -This translation needs to occur at the Bicep compiler level. We need to build in a plugin that understands the Radius types and can convert them to the appropriate output type for the destination hosting platform. It is important that this happens in the Bicep compiler so that it interoperates successfully with the other primitives. - -Example user-facing representation (Future): - - -```sh -resource app 'radius.dev/Application@v1alpha3' = { - name: 'app' - resource website 'Container' = { - name: 'website' - container: { - image: 'radiusteam/mywebsite:latest' - } - } -} -``` - -Translated to ARM: - -```json -{ - "resources": [ - { - "type": "Microsoft.Radius/application", - "apiVersion": "2020-01-01", - "name": "app", - "properties": { - } - }, - { - "type": "Microsoft.Radius/application/Container", - "apiVersion": "2020-01-01", - "name": "website", - "dependsOn": [ - "[resourceId(....)]" - ], - "properties": { - "container": { - "image": "radiusteam/mywebsite:latest" - } - } - } - ] -} -``` - -Translated to Kubernetes: - -```json -{ - "resources": [ - { - "kind": "Application", - "apiVersion": "radius.dev/v1alpha3", - "metadata": { - "name": "app", - "namespace": "mynamespace", - "annotations": { - "radius.dev/application": "app" - } - } - }, - { - "kind": "Container", - "apiVersion": "radius.dev/v1alpha3", - "metadata": { - "name": "app-website", - "namespace": "mynamespace", - "annotations": { - "radius.dev/application": "app", - "radius.dev/resource": "website" - } - }, - "spec": { - "container": { - "image": "radiusteam/mywebsite:latest" - } - } - } - ] -} -``` - -Application model features (Components, Routes, Scopes, Traits) must be defined with JSON schemas so that consistent validation and parsing can be performed across all of the hosting platforms we support. - -Regardless of the hosting platform the bodies of our types (eg. everything inside `spec` in Kubernetes, everything inside `properties` in ARM will be consistent.) By using schemas to define the defintions we can easily support all of these targets in full fidelty because its just the wrappers that are different. This is important to achieve velocity because we will support a large number of these types and want to make authoring them easy. - - -> 🚧 Under Construction 🚧
-We currently do a translation of types but not of structure in the Bicep compiler. We code-generate different ARM types for our output like `radius.dev/Application` -> `Microsoft.CustomProviders/provider/Application`. - -We do not currently perform any translation of the structure of the output. - -### Deployment Engine - -The ARM deployment engine is responsible for translating an ARM JSON template into a set of operations on individual resources. If we have a dependency on Bicep then we have a dependency on the deployment engine since the output of Bicep is an ARM JSON template. - -In Azure the ARM deployment engine is a centrally-hosted component that calls into other resource providers. - -> 🚀 Future State 🚀
-The ARM team plans to decouple the deployment engine and release it as a separate microservice with neutral branding. This is a key enabler for our Kubernetes strategy since we'll conceptually have the same components involved. - -The ARM deployment engine handles the translation from a group of resources with order dependencies to individual operations on resources. - -Example of an ARM JSON template: - -```json -{ - "resources": [ - { - "type": "Microsoft.Radius/applications", - "apiVersion": "2020-01-01", - ... - }, - { - "type": "Microsoft.Radius/applications/components", - "apiVersion": "2020-01-01", - ... - } - ] -} -``` - -Each resource object in the template represent an operation on an individual resource (ARM resource or Kubernetes resource). For an understanding of Radius, it's important to know that we only handle operations on individual resources, not the Bicep file or ARM JSON template as a whole. This is also how interop between Radius types and resources of the hosting platform work deployed in the same template works - the deployment engine manages this. - -### Radius API - -The Radius API implements the contract between the Radius control plane and the control plane of the hosting platform. You can think of the Radius API is an adapter sitting on top of the *Radius control plane*. The Radius API is a running microservice, whereas the *Radius control plane* is more like a library. - -- Azure: Radius API is implemented as a resource provider to give full interop with ARM types and ARM-related tools -- Kubernetes: Radius API is implemented as a controller to give full interop with Kubernetes types and Kubernetes-related tools - -The Radius API will receive application data in the native format of the hosting platform: - -- Azure: ARM resources in JSON format -- Kubernetes: Kubernetes CRDs - -It is the job of the Radius API to translate the application model into its *core representation* and feed it into the *Radius control plane* for processing. - -The Radius API is responsible for data storage of status and tracked output resources: - -- Azure: Radius API has its own database for storage of status and resources -- Kubernetes: Radius API stores status in the CRD status field - -The Radius API is responsible for communicating changes in status and failures via the appropriate channel for the hosting platform: - -- Azure: Radius API implements the ARM-RPC protocol in accordance with ARM's strong consistency semantics -- Kubernetes: Radius API implements validation using webhooks, communicates changes in status using events and the CRD status field - -> 🚧 Under Construction 🚧
-Currently in Azure we implement this with a Custom Resource Provider. This is a feature for public extensibility of the ARM control plane and comes with some limitiations. - -Custom resource providers are per-resource-group, meaning that the RP has to be explicitly provisioned for each resource group where the user wants to deploy applications. - -Custom resource providers have a simplified model for interactions between the RP and ARM and don't include all of the features like preflight validation or what-if. Custom resource provider objects are not visible in the Azure portal. - -We are operating in this mode because building a production RP is a significant investment in upfront cost and ongoing maintenance. Opening up an RP as a preview service for public access has a significant ongoing maintenance cost due to the long deprecation period. - -> 🚀 Future State 🚀
-In the future Radius will have a production multi-tenant RP using the RPaaS progamming model for the managed service. - -In the future Radius will have Kubernetes controllers for its objects as part of the OSS Kubernetes offering. - -#### Radius API in Azure - -> 🚧 Under Construction 🚧
-It is important to understand first of all that a resource provider is just a REST+JSON website that implements the [ARM-RPC Protocol](https://github.com/Azure/azure-resource-manager-rpc). - -The current state in Azure reflects the *user-mode PaaS* stage of the project. We have made architecture decisions that optimize for simplicity, productivity, and cost that would not be acceptable tradeoffs in a production service. - -A brief summary: - -- The RP runs on Azure App Service -- We use CosmosDB Mongo as a database -- We authenticate incoming calls from ARM using a client-certificate (part of custom RP) -- We authenticate for outgoing calls to ARM using a managed identity -- We authenticate for outgoing calls to Kubernetes using credentials we fetch from ARM - -Some of the tradeoffs here: - -- We run a cheap SKU of App Service and CosmosDB to keep costs low -- We don't require a sophisticated authentication system for ARM because we're using custom RP -- We don't support traffic from any other caller than ARM -- We don't support multi-tenancy - each RP manages a single environment (resource group + AKS) -- We don't support many of the more complex ARM features (what-if, preflight) because custom RP doesn't support them -- We don't have any dataplane services (non-ARM services) - -**Why App Service???** is a frequently asked question. Fundamentally an RP is a website that's publicly accessible and has a routable hostname. App Service comes with all of these features built-in and is trivial to manage. - -> 🚀 Future State 🚀
-For building a production RP [RPaaS](https://armwiki.azurewebsites.net/rpaas/overview.html) is the strongly required model. - -The best way to think about RPaaS is that it is a simplified way to implement a resource provider. The actual contract for an RP is [very complex](https://github.com/Azure/azure-resource-manager-rpc). RPaaS moves the storage of the ARM resource data into a centralized system and requires the service to only handle changes to state instead of the whole process for CRUD operations. - -When we move to build a production RP, we'll be able to delete a lot of our code for handling the ARM-RPC contract and storage of the actual resources - we'll be responsible for storing the state associated with the resources instead. - -In this mode we could end up using the same combination of features to host our RPaaS (App Service + CosmosDB). The requirements are the same, an RPaaS is a REST+JSON website. - -Some of the main differences: - -- We would deploy App Service in multiple geos, each in an HA configuration -- Our RP would be multi-tenant (storing many users data) -- We would use an HA geo-replicated SKU of CosmosDB for storing our state -- Our authentication setup will be more complex and fine-grained -- We would use production quality logging and telemetry systems - -#### Radius API in Kubernetes - -> 🚀 Future State 🚀
-We have not built this yet, but we have good clarity on how it will work. - -The architecture for Kubernetes is simple because Kubernetes controllers provide everything we need in a simple model. In Kubernetes all that's needed is the controller(s) - no external storage or external-facing systems are required. - -### Radius control plane - -The Radius control plane is responsible for the *business logic* of deploying and managing applications. This is implemented as a set of libraries that can be incorporated into the Radius API (which has multiple flavors). - -It's important to understand that the control plane layer is isolated from: - -- The wire format used by the hosting platform (ARM JSON or Kubernetes objects) -- How data and status is stored (standalone database or Kubernetes status field) -- How the current state is tracked and queried (ARM resoures or Kubernetes objects cached by a controller) - -These are concerns that are managed a layer above in the Radius API. - -The concerns that are part of the control plane are pluggable due to the variety of different scenarios we target. - -#### Principles - -Our core principle in the control plane layer is the application of declarative desired state to the underlying system through a process of reconciliation. This is the same general process that has made Kubernetes a success. Systems that react to changes in the desired and underlying state are easier to reason about and have self-healing behaviors. - -To summarize this core principle: - -> Radius performs operations in terms of the delta between the desired state and actual statue of the underlying hosting platform - -#### Computing desired state (rendering) - -Since the desired state of the application is computed in terms of the underlying hosting platform it means that Radius needs to have multiple pluggable implementations of the *backend*. - -Example: - -- Azure + AKS: `radius.dev/Container` maps to a Kubernetes deployment -- Azure + Serverless: `radius.dev/Container` maps to an Azure managed service -- Kubernetes: `radius.dev/Container` maps to a Kubernetes deployment - -> 🚧 Under Construction 🚧
-The current implementation of the control plane only understands Azure + AKS as a hosting platform, the *backend* is not pluggable. - -> 🚧 Under Construction 🚧
-The current implementation of the control plane is quite naive and doesn't totally satisfy our requirements. - -> 🚀 Future State 🚀
- -The results of desired state computation (rendering) are a set of objects per-component that reflect the desired state of the hosting platform as well as how to fetch the values of *bindings* (the logical connection points between the components). We call these objects *output resources*. - -Output resources each have an assigned logical name. These names are stable identifiers that represent the *role* of the output resource with respect to the component. - -Output resources are parameterized objects that contain placeholders for values that can only be known when applying the state. These placeholders represent all of the concerns that cannot be reasoned about idempotently: - -- Physical names: runtime-generated names for hosting platform resources -- Bindings: dependencies and connection-points between components - -It is critical the the rendering process of a component has the following characteristics with result in valuable guarantees: - -- Will result in the same output based on the same input - - Guarantee: there are no infinite loops in the operations performed by Radius -- Output resource logical names are stable - - Guarantee: orphaned output resources can be detected and deleted when comparing output resources against the actual state of the system -- Can complete without applying any state changes to the underlying hosting platform - - Guarantee: rendering output can be diffed against current state because current state is not a moving target -- Can complete without knowing the outputs of other components - - Guarantee: the per-operation work done by the control plane scales with complexity rather than application size - -#### Gathering actual state - -In order to apply the desired state we need to reconcile it with the actual state of the hosting platform. This is a pluggable concern that is part of the Radius API and specialized to the hosting environment. - -> 🚧 Under Construction 🚧
-We currently track the *expected* state of resources for Azure in our database. This is not the same as the *actual state* because it is based on our book-keeping and not the real source of truth (ARM). - -Another way of saying this is that we have not implemented drift-detection. We do not provide any guarantees when a user changes or deletes a Radius-managed resource in Azure. - ->❓ Open Question ❓
-We will need to learn from some others how to implement this for Azure. Some other teams that run app-model projects within their team have already implemented good approaches that we can learn from. - -> 🚀 Future State 🚀
-In Kubernetes this is very easy to accomplish, it is built-in to the controller framework. - -#### Applying desired state - -This stage deals with apply the output resources through a series of PUT and PATCH operations. - -We need to communicate with potentially multiple systems in this layer. The set of systems that we need to communicate with is a function of the hosting platform: - -- ARM: needed in Azure-based hosting platforms -- Kubernetes: needed in Kubernetes and Azure + AKS hosting platforms - -Conceptually this is an open set. We could target any hosting platform's native resource format as long as it provides the right guarantees for idempotency. - -> 🚧 Under Construction 🚧
-We currently have a set of hand-coded *handlers* that deal with specified Azure resource types. Over time this will become the exception not the norm. We need to build the processing logic to handle ARM resources in a generic form - and only hand-code special cases when absolutely required. - -> 🚧 Under Construction 🚧
-We currrently build an ordering of all components and apply their desired state in dependency order of the components. This comes with the limitation that cycles in dependecies between output resources of components are not supported. - -> 🚀 Future State 🚀
-In the future we will use the output of the rendering phase to apply state in the dependency order of the output resources, not the dependency order of the components. - -[This issue](https://github.com/project-radius/radius/issues/300) describes the future state. - -### Hosting platform - -The hosting platform is the thing that ultimately runs the infrastructure that makes up the user applications. Conceptually, the hosting platform could be anything ranging from public clouds to a developer's laptop, or IoT devices. - -We require the ability to run containers right now as we don't currently target other forms of compute, but that limitation is not fundamental. - -#### Azure - -> 🚧 Under Construction 🚧
-Due the *user-mode PaaS* phase of the project that we're currently in we've made choices that optimize for simplicitly and velocity. We're using AKS as a compute runtime because it is easy to configure and extend and also allows us to make progress on both Azure ARC and pure Kubernetes hosting platforms. - -This choice comes with some drawbacks, in a few ways it provides a different user-experience than our goal state: - -- The AKS cluster is visible in the user's subscription -- AKS (at least in default config) is a very expensive way to host a small application -- Kubernetes leaks details that are visible to application code (DNS, environment variables) - -> 🚀 Future State 🚀
-The future state for Azure involves us managing serverless compute services directly rather than using AKS as the compute runtime. This will require more investment from us and more explicit management of concerns like networking that are not challenges for us on AKS - ->❓ Open Question ❓
-The exact plans for the compute runtime on Azure are TBD. This has overlap with other product planning discussions and so the discussion about this topic won't take place on GitHub. - -#### Kubernetes - -> 🚀 Future State 🚀
-We have not yet built a standalone Kubernetes hosting platform. However we know a lot about the shape because the options for Kubernetes are public OSS projects. - -Since Kubernetes is already ideal for compute workloads, we only need to answer what will be done for non-compute workloads. The emphasis will be on extensibility and flexibility as Kubernetes itself doesn't provide the answers. - -For example we'll likely provide a built-in solution for common types like *MongoDB* that runs as a container with a non-production level of service. We'll then allow extensibility via: - -- Custom Kubernetes manifests (you provide the template) -- Helm Charts -- Cloud provider operators -- Open Service Broker - -Compared to the Azure offering, it is expected that Kubernetes will require more configuration to deliver the same capabilities. This is reflective of the fact that there are more options and more choices on Kubernetes than on cloud providers with a suite of hosted services. For example we may not provide an on-by-default experience for log aggregation of Kubernetes, but provide the user with several good options to configure one. - -The menu of extensibility and configurabiity is a key call-to-action to build an OSS community. Users are best served by an array of options, and those options are best maintained by those with an interest in those technologies. diff --git a/docs/contributing/architecture.png b/docs/contributing/architecture.png deleted file mode 100644 index 93b18dccd2..0000000000 Binary files a/docs/contributing/architecture.png and /dev/null differ diff --git a/docs/contributing/contributing-code/README.md b/docs/contributing/contributing-code/README.md deleted file mode 100644 index a4395dd010..0000000000 --- a/docs/contributing/contributing-code/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Developing Project Radius - -## What to contribute - -For now, we're looking for help with issues labeled as *Good First Issue*. You can find a query [here](https://github.com/project-radius/radius/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22). - -## Getting started - -For your first commit and PR to Project Radius you should start with the step-by-step [first-commit guide](./contributing-code-first-commit/first-commit-00-prerequisites.md). \ No newline at end of file diff --git a/docs/contributing/contributing-code/contributing-code-azure/README.md b/docs/contributing/contributing-code/contributing-code-azure/README.md deleted file mode 100644 index f1104ac2fa..0000000000 --- a/docs/contributing/contributing-code/contributing-code-azure/README.md +++ /dev/null @@ -1 +0,0 @@ -# Developing the Radius resource provider diff --git a/docs/contributing/contributing-code/contributing-code-azure/logging.md b/docs/contributing/contributing-code/contributing-code-azure/logging.md deleted file mode 100644 index a50c527758..0000000000 --- a/docs/contributing/contributing-code/contributing-code-azure/logging.md +++ /dev/null @@ -1,37 +0,0 @@ -# Radius resource provider logging - -The Radius RP logs will be used for debugging and troubleshooting Radius deployments and end-to-end deployment tests. These logs should therefore provide meaningful information and context which would be needed for troubleshooting. - -## Log Context Passing - -When the RP is created, a new log context is created and information such as the subscription ID, resource group is added to it. This log context is then passed around and every entry point can add more information to the same log context as it becomes available e.g. applicationName, resourceID, etc. - -## Logging Best Practices - -* If a new entry point is introduced, make sure it accepts a context and pass in the main context with the logger. For example: - -```go -func (r *rp) UpdateDeployment(**ctx context.Context**, d *rest.Deployment) (rest.Response, error) { - .... -} -``` - -* Inside a function, create a logger from the input context to log messages. - -```go -logger := logr.FromContextOrDiscard(ctx) -``` - -* Whenever there is more new relevant information that becomes available in a method, add new information fields to the logs. Radius uses a structured format for logging. Add a new constant field under the ucplogger package and add it to the logging context. - -```go -const ( -LogFieldAppName = "applicationName" - ... -) - -ctx = ucplog.WrapLogContext(ctx, - logging.LogFieldAppName, id.App.Name(), - logging.LogFieldAppID, id.App.ID) -logger := logr.FromContextOrDiscard(ctx) -``` diff --git a/docs/contributing/contributing-code/contributing-code-azure/settings.md b/docs/contributing/contributing-code/contributing-code-azure/settings.md deleted file mode 100644 index e46d528b53..0000000000 --- a/docs/contributing/contributing-code/contributing-code-azure/settings.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -type: docs -title: "Radius resource provider settings" -linkTitle: "Resource provider settings" -description: "Settings supported by the Radius resource provider" -weight: 30 ---- - -The Radius Resource Provider supports a number of different settings that will configure its behavior. The primary purpose of the resource provider is support Azure integration, so by default the RP behaviors are optimized towards Azure. - -Unlike the `rad` CLI or other infrastructure, all of the supported settings for the Radius RP are environment variables. - -Many of the optional settings are booleans, which apply the following logic: - -- `true` enables the setting. This value is compared *case-insensitively*, so `True` would also be accepted. -- ANY other value disables the setting. - -Enum values are compared *case-insensitively*. - -## All settings - -| Environment variable | Required / (default value) | Type | Description | -| ------------------------------ | -------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -| PORT | **yes** | int | Configures the HTTP listening port of the RP. Must be a valid port number. | -| SKIP_AUTH | no (false) | boolean | Optionally skip authentication checks for inbound HTTP requests to the RP. | -| MONGODB_CONNECTION_STRING | **yes** | string | Configures the connection string of the MongoDB database used to store resources. | -| MONGODB_DATABASE | **yes** | string | Configures the name of the MongoDB database used to store resources. | -| SKIP_K8S | no (false) | boolean | Optionally skip connecting to Kubernetes. This means that Kubernetes resources will not be supported. -| RP_ID | no | string | Optionally specify a unique identifier for the RP instance which will be used for logging. -| SKIP_ARM | no (false) | boolean | Optionally skip connecting to ARM. This means that Azure resources will not be supported. | -| RADIUS_MODEL | no (`azure`) | enum | Configures the application model to use. This defines the set of support components and output resources. Supported values: `azure`, `k8s`. | -| ARM_SUBSCRIPTION_ID | *when ARM is enabled* | string | Configures the subscription id used for ARM operations. | -| ARM_RESOURCE_GROUP | *when ARM is enabled* | string | Configures the resource group used for ARM operations. | -| ARM_AUTH_METHOD | no (auto) | string | Configures explicitly which type of credentials the RP will use for ARM (UCPCredential,Managed,ServicePrincipal,Cli). By default the RP will autodetect the credential type | -| AZURE_CLIENT_ID | no | string | Configures the client id of a service principal for ARM authentication. | -| AZURE_CLIENT_SECRET | no | string | Configures the client secret of a service principal for ARM authentication. | -| AZURE_TENANT_ID | no | string | Configures the AAD tenant of a service principal for ARM authentication. | -| MSI_ENDPOINT/IDENTITY_ENDPOINT | no | string | Used to detect whether the RP should use managed identity for ARM authentication. | -| RADIUS_LOGGING_JSON | no (`development`) | string | Configures the log profile for Radius | -| RADIUS_LOGGING_LEVEL | *see Logging section* | string | Configures the log level for Radius | - -## ARM authentication - -Authentication with ARM can be disabled totally by setting `SKIP_ARM=true`. This will disable ARM features like creation and management of Azure resources. - -The RP can connect to ARM using credentials from one of three different sources in order of priority: - -- Service Principal -- Managed Identity (used when deployed) -- CLI authentication (used in local development) - -Our detection logic mirrors what the newer Azure Go SDKs do. Since we require the use of the old-style SDKs we also perform the same logic. The environment variables we use to read these settings are the **standard set** used by all Azure tools. eg: `AZURE_CLIENT_ID` is the standard environment variable supported by all Azure tools. - -## Kubernetes - -Authentication with Kubernetes can be disabled totally by setting `SKIP_K8S=true`. This will disable Kubernetes features like creation and management of containers/pods and ingresses. - -The RP connects to Kubernetes using two different strategies to find the identity and credentials in order or priority: - -- Using in-cluster credentials (if present) -- Using local Kubeconfig - -## Logging - -Radius Resource Provider uses the zap logger as the log sink and logr as the interface. - -### Configuring Radius Log Profile -Radius Log Profile can be set using the environment variable RADIUS_LOG_PROFILE. The allowed values are `production` and `development`. This setting controls the output log encoding format, default log level and other related zap logger settings. - -### Configuring Radius Log Level -Radius Log Level can be set using the environment variable RADIUS_LOG_LEVEL. The allowed values are `normal` or `verbose`. If this environment variable is not set, the default log level is determined by the log profile configured above. \ No newline at end of file diff --git a/docs/contributing/contributing-code/contributing-code-building/README.md b/docs/contributing/contributing-code/contributing-code-building/README.md new file mode 100644 index 0000000000..410c45e333 --- /dev/null +++ b/docs/contributing/contributing-code/contributing-code-building/README.md @@ -0,0 +1,60 @@ +# Building the code + +Radius uses a Makefile to build the repository and automate most common repository tasks. + +You can run `make` (no additional arguments) to see the list of targets and their descriptions. + +## Building the repository + +You can build the repository with `make build`. This will build all of the packages and executables. The first time you run `make build` it may take a few minutes because it will download and build dependencies. Subsequent builds will be faster because they can use cached output. + +The following command will build, run unit tests, and run linters. This command is handy for verifying that your local changes are working correctly. + +```sh +make build test lint +``` + +- See further information about tests [here](../contributing-code-tests/). +- See further information about linking [here](../contributing-code-writing/). + +## Building containers + +You can build containers for the Radius services using `make docker-build`, and push them with `make docker-push`. + +By default we will assume your Docker registry is your OS username, and assume you want to build the `latest` tag. You can override this with environment variables. + +- `DOCKER_REGISTRY` - set destination registry +- `DOCKER_TAG_VERSION` - set image tag + +These commands assume you are already logged-in to the registry you are using. If you get errors related to authentication, double-check that you are logged-in. + +Here's an example command that will push and push images to a specified registry: + +```sh +DOCKER_REGISTRY=myregistry.ghcr.io make docker-push docker-build +``` + +If you work with Radius frequently, you may want to define a shell variable as part of your profile to set your registry. + +## Generating code + +If you are updating API schemas, or updating Go APIs that have mocks, you will need to update the generated code as part of your commit. It is our policy that we **check in** generated code. This minimizes the number of people that have to install the generators and wait for them to run. We validate as part of our PR process that the generated files are up to date. + +If you need to do this, first see the [prerequisites](../contributing-code-prerequisites/) for code generation. + +Once you have installed the prerequisites, run the following command and then **commit** the changes as part of your commit. + +```sh +make generate +``` + +This may take a few minutes as there are several steps. + +If you encounter problems please [open an issue](https://github.com/project-radius/radius/issues/new/choose) so we can help. We're trying to make these instructions as streamlined as possible for contributors, your help in identifying problems with the tools and instructions is very much appreciated! + + +## Troubleshooting make + +You might encounter error messages while running various `make` commands due to missing dependencies. Review the [prerequisites](./../contributing-code-prerequisites/) page for installation instructions. + +If you need to report an issue with the Makefile, we will ask you for a dump of the variables. You can see the state of all of the variables our Makefile defines with `make dump`. The output will be quite large so you might want to redirect this to a file. \ No newline at end of file diff --git a/docs/contributing/contributing-code/contributing-code-cli/running-rad-cli.md b/docs/contributing/contributing-code/contributing-code-cli/README.md similarity index 54% rename from docs/contributing/contributing-code/contributing-code-cli/running-rad-cli.md rename to docs/contributing/contributing-code/contributing-code-cli/README.md index c973d356c3..410bd9a68a 100644 --- a/docs/contributing/contributing-code/contributing-code-cli/running-rad-cli.md +++ b/docs/contributing/contributing-code/contributing-code-cli/README.md @@ -4,7 +4,33 @@ For a lot of your development tasks you will need to build `rad` from source ins This is the best way to test changes, and to make sure you have the latest bits (other people's changes). -## Creating an wrapper script (MacOS/Linux) +## Debugging in VS Code + +We provide a debug target `Launch rad CLI` as part of our repo's VS Code configuration. Select `Launch rad CLI` from the drop-down press the Debug button to launch. + +If you need to pass command line arguments into the CLI for testing then you can do this by editing `./vscode/launch.json`. Find the `Launch rad CLI` target and edit the `args` property. + +> ⚠️ VS Code debugging does not support interactive user-input. If you need to debug a command that prompts for confirmation, you can bypass it by passing `--yes` at the command line. This tip does not apply to `rad init` which is always interactive. + +## Installing a local build + +You can use the Makefile to install a local build of Radius. By default this will install to `/usr/local/bin/rad`. You may also need to specify `sudo` depending on the destination and its permissions. + +```sh +sudo make install +``` + +If you need to install to a different location, you can override via the `RAD_LOCATION` environment variable. Make sure the path you choose ends includes `rad` as the filename and is on your `PATH` so it can be executed easily. + +```sh +RAD_LOCATION=/my/custom/location/rad sudo make install +``` + +## Creating a wrapper script + +If you frequently need to work with a local build of `rad` you can create a script that will wrap `go run`. + +> ⚠️ This tip only works when your current working directory is inside the repository. If your shell is outside the repository, then Go won't know how to resolve modules and the build will fail. Create the following script and place it on your path with a name like `dev-rad`. diff --git a/docs/contributing/contributing-code/contributing-code-control-plane/README.md b/docs/contributing/contributing-code/contributing-code-control-plane/README.md new file mode 100644 index 0000000000..c9c302ad78 --- /dev/null +++ b/docs/contributing/contributing-code/contributing-code-control-plane/README.md @@ -0,0 +1,18 @@ +# Contributing to the Radius control-plane + +The Radius control-plane services are the microservices that run to deploy and manage applications and cloud resources. This page is an index of relevant topics for developing with the control-plane. + +You might hear these components referred to as: + +- UCP (Universal control plane): Front-door proxy and integration with cloud resources +- Core RP (`Applications.Core` Resource Provider): Support for core Radius concepts like applications and containers +- Dapr RP (`Applications.Dapr` Resource Provider): Support for Dapr integration +- Datastores RP (`Applications.Datastores` Resource Provider): Support for databases and recipes +- Messaging RP (`Applications.Messaging` Resource Provider): Support for messaging technologies and recipes +- Link RP: Legacy name for Dapr, Datastores, or Messaging RP + +## Table of contents + +- [Configuration](./configSettings.md) +- [Logging](logging.md) +- [Running the control-plane locally](./running-controlplane-locally.md) diff --git a/docs/contributing/contributing-code/contributing-code-azure/configExamples/kubeConfig.png b/docs/contributing/contributing-code/contributing-code-control-plane/configExamples/kubeConfig.png similarity index 100% rename from docs/contributing/contributing-code/contributing-code-azure/configExamples/kubeConfig.png rename to docs/contributing/contributing-code/contributing-code-control-plane/configExamples/kubeConfig.png diff --git a/docs/contributing/contributing-code/contributing-code-azure/configExamples/localConfig.png b/docs/contributing/contributing-code/contributing-code-control-plane/configExamples/localConfig.png similarity index 100% rename from docs/contributing/contributing-code/contributing-code-azure/configExamples/localConfig.png rename to docs/contributing/contributing-code/contributing-code-control-plane/configExamples/localConfig.png diff --git a/docs/contributing/contributing-code/contributing-code-azure/configSettings.md b/docs/contributing/contributing-code/contributing-code-control-plane/configSettings.md similarity index 66% rename from docs/contributing/contributing-code/contributing-code-azure/configSettings.md rename to docs/contributing/contributing-code/contributing-code-control-plane/configSettings.md index 9208b011e3..4592051409 100644 --- a/docs/contributing/contributing-code/contributing-code-azure/configSettings.md +++ b/docs/contributing/contributing-code/contributing-code-control-plane/configSettings.md @@ -1,4 +1,7 @@ -## Summary +## Radius Control-plane configuration and settings + +## Summary + Configuration schemas are used to define the service configuration for the resource provider's execution. The default configurations use the `Applications.Core RP` but configurations can also be set to run the `Applications.Link RP` for private preview and dev/test purposes. If you wanted to locally run Radius with specific configurations, `yaml` files can be created and stored in the `cmd` folder for the corresponding UCP or resource provider. @@ -10,7 +13,7 @@ If you wanted to run Radius on Kubernetes with specific configurations, `yaml` f ![Kubernetes Config](./configExamples/kubeConfig.png) -## Schema +## Config File Schema The following properties can be specified in configuration for all services: | Key | Description | Example | @@ -241,4 +244,68 @@ metricsProvider: enabled: true path: "/metrics" port: 9090 -``` \ No newline at end of file +``` + +## Environment Variables + +> 🚧🚧🚧 Under Construction 🚧🚧🚧 +> +> This section documents legacy environment variables that we have not yet migrated to the configuration file. +> +> Long-term we plan to remove these environment variables and delete this section. + +The Radius control-plane services support a number of different settings that will configure their behavior. + +Unlike the `rad` CLI or other infrastructure, all of the supported settings for the Radius RP are environment variables. + +Many of the optional settings are booleans, which apply the following logic: + +- `true` enables the setting. This value is compared *case-insensitively*, so `True` would also be accepted. +- ANY other value disables the setting. + +Enum values are compared *case-insensitively*. + +### All settings + +| Environment variable | Required / (default value) | Type | Description | +| ------------------------------ | -------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------- | +| PORT | **yes** | int | Configures the HTTP listening port of the RP. Must be a valid port number. | +| SKIP_ARM | no (false) | boolean | Optionally skip connecting to ARM. This means that Azure resources will not be supported. | +| ARM_AUTH_METHOD | no (auto) | string | Configures explicitly which type of credentials the RP will use for ARM (UCPCredential,Managed,ServicePrincipal,Cli). By default the RP will autodetect the credential type | +| AZURE_CLIENT_ID | no | string | Configures the client id of a service principal for ARM authentication. | +| AZURE_CLIENT_SECRET | no | string | Configures the client secret of a service principal for ARM authentication. | +| AZURE_TENANT_ID | no | string | Configures the AAD tenant of a service principal for ARM authentication. | +| MSI_ENDPOINT/IDENTITY_ENDPOINT | no | string | Used to detect whether the RP should use managed identity for ARM authentication. | +| RADIUS_LOGGING_JSON | no (`development`) | string | Configures the log profile for Radius | +| RADIUS_LOGGING_LEVEL | *see Logging section* | string | Configures the log level for Radius | + +### ARM authentication + +Authentication with ARM can be disabled totally by setting `SKIP_ARM=true`. This will disable ARM features like creation and management of Azure resources. + +The RP can connect to ARM using credentials from one of three different sources in order of priority: + +- Service Principal +- Managed Identity (used when deployed) +- CLI authentication (used in local development) + +Our detection logic mirrors what the newer Azure Go SDKs do. Since we require the use of the old-style SDKs we also perform the same logic. The environment variables we use to read these settings are the **standard set** used by all Azure tools. eg: `AZURE_CLIENT_ID` is the standard environment variable supported by all Azure tools. + +### Kubernetes + +Authentication with Kubernetes can be disabled totally by setting `SKIP_K8S=true`. This will disable Kubernetes features like creation and management of containers/pods and ingresses. + +The RP connects to Kubernetes using two different strategies to find the identity and credentials in order or priority: + +- Using in-cluster credentials (if present) +- Using local Kubeconfig + +### Logging + +Radius Resource Provider uses the zap logger as the log sink and logr as the interface. + +#### Configuring Radius Log Profile +Radius Log Profile can be set using the environment variable RADIUS_LOG_PROFILE. The allowed values are `production` and `development`. This setting controls the output log encoding format, default log level and other related zap logger settings. + +#### Configuring Radius Log Level +Radius Log Level can be set using the environment variable RADIUS_LOG_LEVEL. The allowed values are `normal` or `verbose`. If this environment variable is not set, the default log level is determined by the log profile configured above. \ No newline at end of file diff --git a/docs/contributing/contributing-code/contributing-code-control-plane/logging.md b/docs/contributing/contributing-code/contributing-code-control-plane/logging.md new file mode 100644 index 0000000000..2108108f10 --- /dev/null +++ b/docs/contributing/contributing-code/contributing-code-control-plane/logging.md @@ -0,0 +1,89 @@ +# Radius control-plane logging + +Logs can be used for debugging and troubleshooting Radius deployments and end-to-end deployment tests. These logs should therefore provide meaningful information and context which would be needed for troubleshooting. + +In the control-plane we use the [logr](https://github.com/go-logr/logr) interface and [zap](https://github.com/uber-go/zap) as the underlying implementation. Logging statements in the control-plane components MUST use these library and not other APIs like `fmt.Printf` or the built-in `"log"` package. + +> ⚡️⚡️⚡️ Note ⚡️⚡️⚡️ +> +> We do user-visible output differently in the CLI and don't use either `logr` or `zap` in that part of the code. + +## Log Context Passing + + Every HTTP request to the API or work item for the backend will create its own log context with the relevant information (HTTP request URL, resource id, etc). The context is then passed through the call stack. Creating a new context can add more information as it becomes available. + +## Logging Best Practices + +* If a new entry major component is introduced, make sure it accepts a context. For example: + +```go +func (r *rp) UpdateDeployment(ctx context.Context, d *rest.Deployment) (rest.Response, error) { + .... +} +``` + +* If calling a function that accepts a context, make sure to provide the one passed to your function (NOT `context.TODO` or `context.Background`): + +```go +func myFunc(ctx context.Context) { + rp.DoSomething(ctx) +} +``` + +* Inside a function, create a logger from the input context to log messages. + +```go +logger := ucplog.FromContextOrDiscard(ctx) +``` + +* Logging statements should begin with a message followed by optional key-value pairs. Optimize for both the message being readable and the key-value-pairs being searchable. + +```go +logger.Info(fmt.Sprintf("processing cloud resource %s", resourceID), "targetResourceID", resourceID) +``` + +* Use `logger.Error` when logging errors. Only log errors when they are handled. Logging errors where they are simply propagated will result in the same failure being logged many times: + +```go + +// GOOD +err := rp.doThings(ctx) +if err != nil { + // respond to user with HTTP 500 + logger.Err(e, "failed to do things") + response.Write(500) +} + +// BAD +err := rp.doDifferentThings(ctx) +if err != nil { + logger.Err(e, "failed to do different things") + return err +} +``` + +* If you want to add context about a particular type of failure, do this with error wrapping not by logging the error multiple types. + +// GOOD +err := rp.doDifferentThings(ctx) +if err != nil { + return fmt.Errorf("failed to different things: %w", err) +} +``` + +* Whenever there is more new relevant information that becomes available in a method, add new information fields to the logs. Radius uses a structured format for logging. Add a new constant field under the ucplogger package and add it to the logging context. + +```go +const ( +LogFieldAppName = "applicationName" + ... +) + +ctx = ucplog.WrapLogContext(ctx, + logging.LogFieldAppName, id.App.Name(), + logging.LogFieldAppID, id.App.ID) +logger := ucplog.FromContextOrDiscard(ctx) +``` + +## When to log + diff --git a/docs/contributing/contributing-code/running-radius-locally.md b/docs/contributing/contributing-code/contributing-code-control-plane/running-controlplane-locally.md similarity index 96% rename from docs/contributing/contributing-code/running-radius-locally.md rename to docs/contributing/contributing-code/contributing-code-control-plane/running-controlplane-locally.md index ba84226b2c..d0c051e90e 100644 --- a/docs/contributing/contributing-code/running-radius-locally.md +++ b/docs/contributing/contributing-code/contributing-code-control-plane/running-controlplane-locally.md @@ -1,5 +1,9 @@ # Running Radius control plane provider locally +> 🚧🚧🚧 Under Construction 🚧🚧🚧 +> +> This guide refers to an internal repo that can only be accessed by the Radius team. This will be updated as we migrate to public resources (running deployment engine in a container). + Radius consists of a few processes that get deployed inside a Kubernetes cluster. This includes: diff --git a/docs/contributing/contributing-code/contributing-code-first-commit/README.md b/docs/contributing/contributing-code/contributing-code-first-commit/README.md index 5536256d1b..3adc767995 100644 --- a/docs/contributing/contributing-code/contributing-code-first-commit/README.md +++ b/docs/contributing/contributing-code/contributing-code-first-commit/README.md @@ -1,3 +1,3 @@ # Making your first commit to Radius -Step by step walkthrough for contributing to the Project Radius codebase for those new to the project +This is a step-by-step walkthrough for contributing to the Project Radius codebase for those new to the project. In this walkthrough, you'll install prerequisites, learn how to debug the `rad` CLI and commit a code change. diff --git a/docs/contributing/contributing-code/contributing-code-first-commit/first-commit-00-prerequisites.md b/docs/contributing/contributing-code/contributing-code-first-commit/first-commit-00-prerequisites.md index af1c77dbd2..aec94672f3 100644 --- a/docs/contributing/contributing-code/contributing-code-first-commit/first-commit-00-prerequisites.md +++ b/docs/contributing/contributing-code/contributing-code-first-commit/first-commit-00-prerequisites.md @@ -1,5 +1,9 @@ # Your first commit: Prerequisites + + ## Operating system We support developing on macOS, Linux and Windows with [WSL](https://docs.microsoft.com/windows/wsl/install). diff --git a/docs/contributing/contributing-code/contributing-code-first-commit/first-commit-01-development-tools.md b/docs/contributing/contributing-code/contributing-code-first-commit/first-commit-01-development-tools.md index 1afc03614d..e1c5178405 100644 --- a/docs/contributing/contributing-code/contributing-code-first-commit/first-commit-01-development-tools.md +++ b/docs/contributing/contributing-code/contributing-code-first-commit/first-commit-01-development-tools.md @@ -1,5 +1,9 @@ # Your first commit: Development tools + + ## Editor This guide covers basic development tasks for Go in Visual Studio Code. The experience with VS Code is high-quality and approachable for newcomers. diff --git a/docs/contributing/contributing-code/contributing-code-first-commit/first-commit-06-creating-a-pr/index.md b/docs/contributing/contributing-code/contributing-code-first-commit/first-commit-06-creating-a-pr/index.md index 3079f3729b..a638bbf02a 100644 --- a/docs/contributing/contributing-code/contributing-code-first-commit/first-commit-06-creating-a-pr/index.md +++ b/docs/contributing/contributing-code/contributing-code-first-commit/first-commit-06-creating-a-pr/index.md @@ -17,7 +17,7 @@ Now you've got something to work on. Once you've developed and tested your chang Before proceeding, make sure your changes pass all the unit tests as well as [golint](https://golangci-lint.run/usage/install/#local-installation). ```sh -make lint && make test +make build lint test ``` It is best if you can resolve problems identified here before submitting. diff --git a/docs/contributing/contributing-code/code-organization/README.md b/docs/contributing/contributing-code/contributing-code-organization/README.md similarity index 95% rename from docs/contributing/contributing-code/code-organization/README.md rename to docs/contributing/contributing-code/contributing-code-organization/README.md index fb4e530eb7..afcabd377b 100644 --- a/docs/contributing/contributing-code/code-organization/README.md +++ b/docs/contributing/contributing-code/contributing-code-organization/README.md @@ -1,5 +1,9 @@ # Understanding Radius repo code organization +> 🚧🚧🚧 Under Construction 🚧🚧🚧 +> +> This information is (sadly) out of date. Please bear with us while we remodel. + This document describes the high-level organization of code for the Radius repository. The goal of this document is to capture most of the important details, not every single thing will be described here. In general you should ask for guidance before creating a new top-level folder in the repo or creating a new folder in `pkg/`. There is usually a better place to put something. diff --git a/docs/contributing/contributing-code/contributing-code-prerequisites/README.md b/docs/contributing/contributing-code/contributing-code-prerequisites/README.md new file mode 100644 index 0000000000..fafadb0bdb --- /dev/null +++ b/docs/contributing/contributing-code/contributing-code-prerequisites/README.md @@ -0,0 +1,121 @@ +# Repository Prerequisites + +This page lists the prerequisites for working with the repository. Most contributors should start with the basic prerequisites. Depending on the task you need to perform, you may need to install more tools. + +## Operating system + +We support developing on macOS, Linux and Windows with [WSL](https://docs.microsoft.com/windows/wsl/install). + +## Basic Prerequisites + + + +### Required tools + +This is the list of core dependencies to install for the most common tasks. In general we expect all contributors to have all of these tools present: + +- [Git](https://git-scm.com/downloads) +- [Go](https://golang.org/doc/install) +- [Node.js](https://nodejs.org/en/) +- [Python](https://www.python.org/downloads/) +- [Golangci-lint](https://golangci-lint.run/usage/install/#local-installation) +- [jq](https://jqlang.github.io/jq/download/) + +- Make + + **Linux**: Install the `build-essential` package: + ```bash + sudo apt-get install build-essential + ``` + **Mac**: + Using Xcode: + ```bash + xcode-select --install + ``` + Using Homebrew: + ```bash + brew install make + ``` + + +#### Testing Required Tools + +If you have not already done so, clone the repository and navigate there in your command shell. + +You can build the main outputs using `make`: + +```sh +make build && make lint +``` + +Running these steps will run our build and lint steps and verify that the tools are installed correctly. If you get stuck or suspect something is not working in these instructions please [open an issue](https://github.com/project-radius/radius/issues/new/choose). + +### Editor + +If you don't have a code editor set up for Go, we recommend VS Code. The experience with VS Code is high-quality and approachable for newcomers. + +Alternatively, you can choose whichever editor you are most comfortable for working on Go code. Feel free to skip this section if you want to make another choice. + +- [Visual Studio Code](https://code.visualstudio.com/) +- [Go extension](https://marketplace.visualstudio.com/items?itemName=golang.go) + +Install both of these and then follow the steps in the *Quick Start* for the Go extension. + +The extension will walk you through an automated install of some additional tools that match your installed version of Go. + +**Launching VSCode** + +The best way to launch VS Code for Go is to do *File* -> *Open Folder* on the repository. + +You can easily do this from the command shell with `code .`, which opens the current directory as a folder in VS Code. + +## Additional Tools + +### Containers + +[Docker](https://docs.docker.com/engine/install/) is required to build our containers. + +### Kubernetes + +The easiest way to run Radius is on Kubernetes. To do this you will need the ability to create a Kubernetes cluster as well as to install `kubectl` to control that cluster, you probably also want Helm to install things in your cluster. There are many ways to create a Kubernetes cluster that you can use for development and testing. If you don't have a preference we recommend `kind`. + +- [Install kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) +- [Install Helm](https://helm.sh/docs/intro/install/) +- [Install Kind](https://kubernetes.io/docs/tasks/tools/#kind) + +#### Troubleshooting Kubernetes + +You might want tools that can help debug Kubernetes problems and understand what's going on in the cluster. Here are some recommendations from the team: + +- [Lens (UI for Kubernetes)](https://k8slens.dev/) +- [VS Code Kubernetes Tools](https://marketplace.visualstudio.com/items?itemName=ms-kubernetes-tools.vscode-kubernetes-tools) +- [Stern (console logging tool)](https://github.com/stern/stern#installation) + +### Dapr + +Radius includes integration with [Dapr](https://docs.dapr.io/). To use work on these features, you'll need to install the Dapr CLI. + +- [Dapr](https://docs.dapr.io/getting-started/install-dapr-cli/) + +### Code Generation + +Our code generation targets are used to update generated OpenAPI specs and generated Go code based on those OpenAPI specs. Additionally, some Go code is generated mocks or Kubernetes API types. + +If you were trying to run `make generate` and ran into an error, then one of the below is likely missing. + +Enter the following commands to install all of the required tools. + +```sh +npm install -g autorest +npm install -g oav +go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.9.1 +go install github.com/golang/mock/mockgen@v1.5.0 +``` + +### Test summaries + +The default `go test` output can be hard to read when you have many tests. We recommend `gotestsum` as a tool to solve this. Our `make test` command will automatically use `gotestsum` if it is available. + +- [gotestsum](https://github.com/gotestyourself/gotestsum#install) \ No newline at end of file diff --git a/docs/contributing/contributing-code/contributing-code-tests/README.md b/docs/contributing/contributing-code/contributing-code-tests/README.md index 47731e4442..fad02255cc 100644 --- a/docs/contributing/contributing-code/contributing-code-tests/README.md +++ b/docs/contributing/contributing-code/contributing-code-tests/README.md @@ -1 +1,41 @@ # Running Radius tests + +## Types of tests + +We apply the [testing pyramid](https://martinfowler.com/articles/practical-test-pyramid.html) to divide our tests into groups for each feature. + +- Unit tests: exercise functions and types directly +- Integration tests: exercise features working with dependencies +- Functional test (also called end-to-end tests): exercise features in realistic user scenarios + +## Unit tests + +Unit tests can be run with the following command: + +```sh +make test +``` + +We require unit tests to be added for new code as well as when making fixes or refactors in existing code. As a basic rule, ideally every PR contains some additions or changes to tests. + +Unit tests should run with only the [basic prerequisites](../contributing-code-prerequisites/) installed. Do not add external dependencies needed for unit tests, prefer integration tests in those cases. + +## Integration tests + +> 🚧🚧🚧 Under Construction 🚧🚧🚧 +> +> We don't currently define targets for integration tests. However we **do** have tests that require optional dependencies, and thus should be moved from the unit test category to the integration tests. + +## Functional tests + +Functional tests have their own dedicated set of [instructions](./running-functional-tests.md). + +Functional tests generally use Radius to deploy an application and then make assertions about the state of that application. We have our infrastructure for this including a "test application" (`magpiego`) and our own test framework for deployment and verification. + +## Test infrastructure and frameworks + +We prefer to write unit tests in a straightforward style, and make sure of [testify](https://github.com/stretchr/testify) for assertions. + +We like the productivity benefits of [subtests](https://go.dev/blog/subtests) and [table-driven tests](https://dave.cheney.net/2019/05/07/prefer-table-driven-tests) and apply these patterns where appropriate. + +We measure code coverage as part of the PR process because it provides a useful insight into whether the right tests are being added. \ No newline at end of file diff --git a/docs/contributing/contributing-code/contributing-code-writing/README.md b/docs/contributing/contributing-code/contributing-code-writing/README.md new file mode 100644 index 0000000000..206041cf0c --- /dev/null +++ b/docs/contributing/contributing-code/contributing-code-writing/README.md @@ -0,0 +1,58 @@ +# Contributing to Radius code + +This guide includes background and tips for working on the Radius Go codebase. + +## Learning Go + +Go is a great language for newcomers! Due to its simple style and uncomplicated design, we find that new contributors can get *going* without a long learning process. + +For learning Go, we recommend the following resources: + +- [Tour of Go](https://go.dev/tour/welcome/1) +- [Effective Go](https://go.dev/doc/effective_go) +- [Offical tutorials](https://go.dev/doc/) + +We're happy to accept pull-requests and give code review feedback aimed at newbies. If you have programmed in other languages before, we are confident you can pick up Go and start contributing easily. + +## Getting productive + +You'll want to run the following command often: + +```sh +make build test lint +``` + +This will build, run unit tests, and run linters to point out any problems. It's a good idea to run this if you're about to make a `git commit`. + +If you're looking for something, use the [code organization guide](./../contributing-code-organization/) to find what you're looking for. + +## Coding style & linting + +We enforce coding style through using [gofmt](https://pkg.go.dev/cmd/gofmt). + +We stick to the usual philosophy of Go projects regarding styling, meaning that we prefer to avoid bikeshedding and debates about styling: + +> gofmt isn't anybody's preferred style, but it's adequate for everybody. + +If you're using a modern editor with Go support, chances are it is already integrated with `gofmt` and this will mostly be automatic. If there's any question about how to style a piece of code, following the style of the surrounding code is a safe bet. + +--- + +We also *mostly* agree with [Google's Go Style Guide](https://google.github.io/styleguide/go/), but don't follow it strictly or enforce everything written there. If you're new to working on a Go project, this is a great read that will get you thinking critically about the small decisions you will make when writing Go code. You can find an appendix further down with some cases where we disagree with and don't follow their guidance. + +### Documentation + +One thing we do require is [godoc comments](https://tip.golang.org/doc/comment) on **exported** packages, types, variables, constants, and functions. We like this because it has two good effects: + +- Encourages you to minimize the exported surface-area, thus simplifying the design. +- Requires you to document clearly the purpose code you expect other parts of the codebase to call. + +Right now we don't have automated enforcement of this rule, so expect it to come up in code review if you forget. + +### Linting + +We run [golint-ci](https://github.com/golangci/golangci-lint) as part of the pull-request process for static analysis. We don't have many customizations and mostly rely on the defaults. + +## Appendix: style guidance we don't follow + +We mostly ignore the Google style guide's [guidance for testing](https://google.github.io/styleguide/go/decisions#assertion-libraries). In particular, we really like [assertion libraries](https://github.com/stretchr/testify) and use them in our tests. diff --git a/docs/contributing/contributing-code/debugging-go-with-vscode.md b/docs/contributing/contributing-code/debugging-go-with-vscode.md deleted file mode 100644 index acaddbefac..0000000000 --- a/docs/contributing/contributing-code/debugging-go-with-vscode.md +++ /dev/null @@ -1,111 +0,0 @@ -# Debugging Radius with Visual Studio Code - -VSCode has good support for debugging VSCode, it's just a little unintuitive to set up. - -VSCode's configuration for the debugger lives in `.vscode/launch.json` in the repo. We don't check this file in, and so everyone can maintain their own set of profiles/aliases. - -## Debugging tests - -Debugging unit tests is easy. Codelens on the test function will offer you a run or debug option, and you just click. No setup needed. - -## Basic debugging - -The most basic configuration for Go looks like this: - -```json -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Launch file", - "type": "go", - "request": "launch", - "mode": "debug", - "program": "${file}" - }, - ] -} -``` - -This example will allow you to launch the debugger with whatever file open in the editor as the entry point. - -To use this open a file like `cmd/rad/main.go` and press the green triangle button. - -## Building aliases - -While that option is flexible, it's not super convenient because it depends on the focus of the editor. - -You can create your own aliases as well, and select them from the drop down. - -```json -{ - "version": "0.2.0", - "configurations": [ - ... - - { - "name": "Launch RP", - "type": "go", - "request": "launch", - "mode": "debug", - "program": "${workspaceFolder}/cmd/rp/main.go", - "env": [ ... environment variables here ...] - "args": [ ... args here ...] - }, - ] -} -``` - -## Debugging interactive commands - -At the time of writing of this document, interactive commands don't work with vanilla Go debugging in vs-code. However there is (a somewhat ugly) but useful way of still being able to debug. - -For this case you will need to create an alias and a task. However, for convenience and usability it's very important that we create scriptable version of everything we do interactively since we can't easily debug the interactive version! - -Here's an example alias (`.vscode/launch.json`): - -```json -{ - "version": "0.2.0", - "configurations": [ - ... - - { - "name": "Debug: rad init azure (interactive mode)", - "preLaunchTask": "start dlv-dap debugger", - "type": "go", - "request": "launch", - "mode": "debug", - "port": 2345, - "host": "127.0.0.1", - "program": "${workspaceFolder}/cmd/rad/main.go", - "args": [ - "env", "init", "azure", "-i" - ] - } - ] -} -``` -With the corresponding task definition (`.vscode/tasks.json`) -PS: Make sure you have `$GOPATH` set in your shell environment. - -```json -{ - "version": "2.0.0", - "tasks": [ - ... - - { - "label": "start dlv-dap debugger", - "type": "shell", - "command": "${env:GOPATH}/bin/dlv-dap dap --headless --listen=:2345 --log --api-version=2", - "problemMatcher": ["$go"], - "group": { - "kind": "build", - "isDefault": true - }, - "isBackground": true, - } - ] -} -``` \ No newline at end of file diff --git a/docs/contributing/contributing-components.md b/docs/contributing/contributing-components.md deleted file mode 100644 index 112d4d7ff1..0000000000 --- a/docs/contributing/contributing-components.md +++ /dev/null @@ -1,37 +0,0 @@ -# Contributing to Project Radius documentation - -> 👷‍♂️ Under construction 🚧
-This page is still under construction. Please come back soon once the Radius team has time to plan out how to create components in an extensible way. - -## Documentation - -All components need to have a page under the [Resource library](https://github.com/project-radius/docs/tree/edge/docs/content/resources). Each page needs to have: - -- Overview section which describes what the component does and why people would use it. -- Configuration section which describes every value which you could provide when defining a component, along with example values for each field. -- Bindings section which describes every bindings the component can provide. -- Traits section which describes every trait that component can have. -- Code example section which describes what the component is and what it does. - -## JSON Schema - -### Adding a new Component schema - -- Under the directory `pkg/rp/schema/components`, add a JSON Schema file for your Component. See existing Components for example, and also take a look at [JSON Schema Draft 4](https://json-schema.org/specification-links.html#draft-4) for more information. -- In your JSON schema, make sure that the new Component inherits from TrackedResource or Proxy Resource, look at existing components JSON schema to see how it is done. ->> `TrackedResource` means that a copy of your resource is stored by centralized servers in Azure. When a GET happens, it will hit the cache. TrackedResource also has to support tags and also have to have a location. Generally a top level resource is tracked (Application). ->> `ProxyResource` means that your RP can change the state dynamically. When a GET happens, it will go through to your RP. -- Register your schema in the manifest file at `pkg/rp/schema/resource-types.json`. -- Add some tests to confirm your JSON schema in the `pkg/rp/schema/testdata/{componentName}` directory. Any JSON file with `*-valid.json` suffix should be accepted by your new schema. Any JSON file with `*-invalid.json` suffix should be rejected by your new schema, with errors matching the content of `*-invalid.txt` file in the same directory. - -### Adding a new Trait schema - -- Under the directory `pkg/rp/schema/traits`, add a JSON Schema for your new trait. Note that the `kind` field must be an enum string having an exactly one value. See existing JSON Schema in the same directory as examples. -- Update `pkg/rp/schema/traits.json` to refer to your new Trait. - -## OpenAPI spec - -The OpenAPI specs are in: -- schemas/rest-api-specs: containing latest Radius API spec. - -OpenAPI specs are autogenerated from the JSON Schema of Components (and other Radius resources) so no need to update the OpenAPI spec when contributing a new component. You will just need to run `make generate` and add the generated diff into your PRs. diff --git a/docs/contributing/contributing-issues/README.md b/docs/contributing/contributing-issues/README.md new file mode 100644 index 0000000000..f952bc5b5f --- /dev/null +++ b/docs/contributing/contributing-issues/README.md @@ -0,0 +1,33 @@ +# Contributing Issues + +You can open an issue using the form [here](https://github.com/project-radius/radius/issues/new/choose). This form will ask you to fill out a template based on the kind of issue you choose. Please fill out the form as this will help us respond to your issue. + +## Tips for creating good issues + +### Use the correct template + +You will save us (the maintainers) time if you want to use the right template. + +- Choose 'Bug Report' if some functionality in Radius is broken, crashing, or not working as advertised. +- Choose 'Feature Request' if you have new ideas for us, or think some existing functionality should work differently. +- Choose 'Open a blank issue' (at the bottom) if neither of those is a good fit. + +### Focus on the repro steps + +Providing clear repro steps with code samples is the best way to get a good response to your issue. [here](https://github.com/project-radius/radius/issues?q=is%3Aissue+is%3Aclosed)'s an example. + +Remember that another human will need to read your instructions and try to reproduce your steps to understand the issue. + +### Tell us what you tried + +If you tried to troubleshoot or workaround the problem please tell us what you tried. This will often save a lot of time in bug investigation and might help others that are working through the same issue. + +### Include screenshots + +You can paste screenshots directly into a Github issue! + +### Include logs + +The command `rad debug-logs` will connect to your cluster, and download the logs from all of Radius' components. This will output a file `debug-logs.zip` which you can attach to your issue. + +Please feel free to inspect the content in `debug-logs.zip` for privacy and security before uploading. If you attach the logs to your issue then they will be public for all to see. \ No newline at end of file diff --git a/docs/contributing/contributing-pull-requests/README.md b/docs/contributing/contributing-pull-requests/README.md new file mode 100644 index 0000000000..b40786b98f --- /dev/null +++ b/docs/contributing/contributing-pull-requests/README.md @@ -0,0 +1,81 @@ +# Contributing Pull Requests + +## What to work on + +We welcome small pull request contributions from anyone (docs improvements, bug fixes, minor features.) as long as they follow a few guidelines: + +- For very minor changes like correcting a typo feel free to just send a pull request without any ceremony. Otherwise ... +- Please start by [choosing an existing issue](https://github.com/project-radius/radius/issues), or [opening an issue](https://github.com/project-radius/radius/issues/new/choose) to work on. +- The maintainers will respond to your issue, please work with the maintainers to ensure that what you're doing is in scope for the project before writing any code. +- If you have any doubt whether a contribution would be valuable, feel free to ask. + +We the maintainers have discretion over what features and pull requests we accept. Please understand that we are responsible for the long-term support and maintenance of Radius, and so we sometimes need to make hard decisions to limit the scope. For another perspective on this, we really like this [article](https://www.igvita.com/2011/12/19/dont-push-your-pull-requests/). + +## Sending a pull request + +> 💡 If you're new to Go or new to open source, our [first commit guide](./../contributing-code/contributing-code-first-commit/) can walk you through the process of making code changes and submitting a pull request. + +Please open pull requests against the `main` branch (the default) unless otherwise instructed. + +When opening a pull request, the form will be pre-populated with our template. Please fill out the template to provide structure to your PR message. If you've already written a good commit message (see below) it will be easy to use with our template. + +A pull request will need to pass the following checkpoints to be accepted: + +- Initial review: a maintainer will review your summary and make sure an appropriate issue is linked +- Testing: automated tests will run against your changes +- Code review: you will get feedback from a maintainer or other contributors in the form of comments + +We expect that contributors have run basic validations (`make build test lint`) before sending a pull request. See [building the repo](../contributing-code/contributing-code-building/) for more information. If you get stuck during this step feel free to open the pull request anyway and ask for help. + +Keep reading for some tips about how to get your pull requests accepted! + +## Writing a good commit message + +We value good commit messages that are descriptive and meaningful at a glance. A good format to follow is like the following: + +```txt + + +Fixes: # + + + +- a summary of the changes being made +- the rationale for the change +- (optional) anything tricky or difficult as a heads up for reviewers +- (optional) additional follow up work that should be done (with links) +``` + +We **squash** pull-requests as part of the merge process, which means that intermediate commits will have their messages appended. We prefer to have a single commit in the git history for each PR. + +## Automated tests + +Our GitHub Actions workflows will run against your pull request to validate the changes. This will run the unit tests, integration tests, and functional tests. + +Ideally everything works the first time, but you may not be so lucky! Our automation will add comments to your pull request that helps explain what's happening. This will include links to logs where you can diagnose what's happening. + +If you get stuck with a failure you can't understand, feel free to ask the maintainers for help. + +## Copilot Summary + +Our pull-request template includes a summary from Github Copilot. This will generate a description of your changes as well as links to the most relevant files. + +You can find an example [here](https://github.com/project-radius/radius/pull/5614). + +## Code review + +The maintainers or other contributors will add comments to your pull request giving feedback, asking questions, and making suggestions. Please respond to these comments to either continue the discussion or explain whether or not you plan to address the feedback. Ultimately, accepting a pull request is at the maintainer's discretion. + +### Being proactive + +It can be helpful for you to comment on your own PR to point out relevant locations, decisions, opportunities for feedback, and tricky parts. This will help reviewers focus their attention as well as save them time. + +### Resolving Feedback + +You can "resolve" comments on your pull request when you've addressed the feedback: either through discussion or through making a code change. As the contributor of the pull-request feel free to mark comments as resolved when you feel like you've done a reasonable job addressing the feedback. + +If you are the code reviewer, it's your responsibility to follow up (politely) if you feel your feedback has not been addressed adequately. + +### Participating in code review + +We welcome any contributor or community member to engage with any pull request on our repository. Feel free to make suggestions for improvements and ask questions that are relevant. If you're asking questions for your learning, please make it clear that your questions are "non-blocking" for the pull request. \ No newline at end of file diff --git a/docs/contributing/contributing-code/release-process.md b/docs/contributing/contributing-releases/READMD.md similarity index 98% rename from docs/contributing/contributing-code/release-process.md rename to docs/contributing/contributing-releases/READMD.md index d995a940c2..bb0e5550de 100644 --- a/docs/contributing/contributing-code/release-process.md +++ b/docs/contributing/contributing-releases/READMD.md @@ -1,5 +1,9 @@ # How to create and publish a Project Radius release +> 🚧🚧🚧 Under Construction 🚧🚧🚧 +> +> This guide refers to resources and processes that can only be accessed by the Radius team. This will be updated as we migrate to public resources like GitHub releases. + Our release process for Project Radius is based on git tags. Pushing a new tag with the format: `v...` will trigger a release build. ## Pre-requisites diff --git a/docs/contributing/how-to.md b/docs/contributing/how-to.md new file mode 100644 index 0000000000..786b0655bb --- /dev/null +++ b/docs/contributing/how-to.md @@ -0,0 +1,21 @@ +# How to contribute + +We welcome and encourage users to contribute to the Radius open-source project in various ways. By joining our community, you can make a meaningful impact and help shape the future of this project. Here are some ways you can get involved: + + Learn how: Browse our guides for how to [install repository prerequisites](./contributing-code/contributing-code-prerequisites/), [build the code](./contributing-code/contributing-code-building/), [understand the code](./contributing-code/contributing-code-organization/), [write code for the project](./contributing-code/contributing-code-writing/), and [run tests](./contributing-code/contributing-code-tests/). This is essential knowledge for working with the repository. + + Tackle small tasks: Start by addressing small issues or tasks labeled as ["good first issues"](https://github.com/project-radius/radius/issues?q=is:issue+is:open+label:%22good+first+issue%22) This allows you to familiarize yourself with the project and make valuable contributions without a steep learning curve. + + Fork the project: Create a personal copy (fork) of the Radius repository on GitHub. This enables you to make changes and experiment as well as submit pull requests. + + Submit pull requests: Once you've made changes or improvements to your forked repository, [submit a pull request](./contributing-pull-requests/) to the main project. Provide clear descriptions of the purpose and benefits of your changes. + + Engage with the community: Participate in discussions, forums, and chat channels related to Radius. Seek guidance, offer help to others, and build connections within the community. + + Test and report bugs: Assist in testing Radius by [identifying and reporting bugs](./contributing-issues/). Detailed bug reports help us address issues promptly and enhance the software's quality. + + Improve documentation: Enhance the project's [documentation](https://github.com/project-radius/docs) by updating existing content, adding guides, or adding examples. Well-documented projects are easier to use and attract more users. + + Spread the word: Share your positive experiences with Radius through blog posts, talks, or social media. Promote the project to attract more users and contributors. Star the project on GitHub! + +Join us in shaping the future of Radius. Together, we can build a robust and innovative open-source project. Happy contributing! \ No newline at end of file diff --git a/docs/uml/enable-local-environments-to-deploy-azure-resources/fig-1-user-creates-spn.png b/docs/uml/enable-local-environments-to-deploy-azure-resources/fig-1-user-creates-spn.png deleted file mode 100644 index eab8e41dca..0000000000 Binary files a/docs/uml/enable-local-environments-to-deploy-azure-resources/fig-1-user-creates-spn.png and /dev/null differ diff --git a/docs/uml/enable-local-environments-to-deploy-azure-resources/fig-1-user-creates-spn.puml b/docs/uml/enable-local-environments-to-deploy-azure-resources/fig-1-user-creates-spn.puml deleted file mode 100644 index 711c002afb..0000000000 --- a/docs/uml/enable-local-environments-to-deploy-azure-resources/fig-1-user-creates-spn.puml +++ /dev/null @@ -1,24 +0,0 @@ -@startuml -skinparam responseMessageBelowArrow true -!define AzurePuml https://raw.githubusercontent.com/plantuml-stdlib/Azure-PlantUML/master/dist - -title Figure 1: User creates a Service Principal Name (SPN) - -actor User as user -participant "Azure CLI" as az - -user -> az: ""az ad sp create-for-rbac -n radius-foobar"" -az --> user: - -note over user #LightGray - - { - "appId": "00000000-0000-0000-0000-000000000000", - "displayName": "radius-foobar", - "password": "superSecretString", - "tenant": "00000000-0000-0000-0000-000000000000" - } - -end note - -@enduml \ No newline at end of file diff --git a/docs/uml/enable-local-environments-to-deploy-azure-resources/fig-2-radius-environment.png b/docs/uml/enable-local-environments-to-deploy-azure-resources/fig-2-radius-environment.png deleted file mode 100644 index 9cd1c2ca65..0000000000 Binary files a/docs/uml/enable-local-environments-to-deploy-azure-resources/fig-2-radius-environment.png and /dev/null differ diff --git a/docs/uml/enable-local-environments-to-deploy-azure-resources/fig-2-radius-environment.puml b/docs/uml/enable-local-environments-to-deploy-azure-resources/fig-2-radius-environment.puml deleted file mode 100644 index 70696cfa7a..0000000000 --- a/docs/uml/enable-local-environments-to-deploy-azure-resources/fig-2-radius-environment.puml +++ /dev/null @@ -1,65 +0,0 @@ -@startuml - - -' Kubernetes -!define KubernetesPuml https://raw.githubusercontent.com/dcasati/kubernetes-PlantUML/master/dist - -!includeurl KubernetesPuml/kubernetes_Common.puml -!includeurl KubernetesPuml/kubernetes_Context.puml -!includeurl KubernetesPuml/kubernetes_Simplified.puml - -!includeurl KubernetesPuml/OSS/KubernetesApi.puml -!includeurl KubernetesPuml/OSS/KubernetesSecret.puml -!includeurl KubernetesPuml/OSS/KubernetesPod.puml - -' Azure -!define AzurePuml https://raw.githubusercontent.com/plantuml-stdlib/Azure-PlantUML/master/dist - -' !includeurl AzurePuml/AzureCommon.puml -!includeurl AzurePuml/AzureSimplified.puml - -!includeurl AzurePuml/Management/AzureManagementPortal.puml -!includeurl AzurePuml/Identity/AzureActiveDirectory.puml - -skinparam maxMessageSize 150 -!define Rel_(e_alias1, e_alias2, e_label, e_direction="") e_alias1 e_direction e_alias2 : "[e_label]" -' !define Rel_(e_alias1, e_alias2, e_label, e_techn, e_direction="") e_alias1 e_direction e_alias2 : "e_label\n//[e_techn]//" - -actor "User" as user -rectangle "Radius CLI" as rad - -!$a = "rad env init dev \ -~--provider-azure \ -~--provider-azure-subscription={{subscription_id}} \ -~--provider-azure-resource-group={{rg_id}} \ -~--provider-azure-client-id={{appId}} \ -~--provider-azure-client-secret={{password}} \ -~--provider-azure-tenant-id={{tenant}}" - -Rel_R(user, rad ,$a) - - - - -'Kubernetes Components -Cluster_Boundary(cluster, "Radius Environment\n Standalone") { - KubernetesApi(k8sAPI, "Kubernetes API", "") - Namespace_Boundary(ns, "radius-system") { - Service_Boundary(de, "Deployment Engine") { - KubernetesSecret(s, "radius-rp", "") - KubernetesPod(depod, "", "") - } - } -} - -AzureManagementPortal(arm, "ARM", "") -AzureActiveDirectory(aad, "AAD", "") - -Rel(rad, k8sAPI, "deploy(helm_chart)") -Rel_Neighbor(s, depod, "secret is loaded to env") -Rel_D(depod, arm, "create(auth_token, subscription_id, rg_id, sazure_resource)") -Rel_R(depod, aad, "get_auth_token(client_id, tenant_id, client_secret)") -Rel(k8sAPI, ns, "deploy radius components") - - -@enduml \ No newline at end of file diff --git a/pkg/cli/prompt/prompt.go b/pkg/cli/prompt/prompt.go index 713c19398a..f48bcf15af 100644 --- a/pkg/cli/prompt/prompt.go +++ b/pkg/cli/prompt/prompt.go @@ -44,7 +44,7 @@ type Interface interface { // GetListInput prompts user to select from a list. Will return ErrExitConsole if the user cancels. GetListInput(items []string, promptMsg string) (string, error) - // RunProgram runs a bubbletea program and blocks until the the program exits. + // RunProgram runs a bubbletea program and blocks until the program exits. // // To create a cancellable program, use the options to pass a context.Context into the program. RunProgram(program *tea.Program) (tea.Model, error) @@ -102,7 +102,7 @@ func (i *Impl) GetListInput(items []string, promptMsg string) (string, error) { return lm.Choice, nil } -// RunProgram runs a bubbletea program and blocks until the the program exits. +// RunProgram runs a bubbletea program and blocks until the program exits. func (i *Impl) RunProgram(program *tea.Program) (tea.Model, error) { return program.Run() } diff --git a/pkg/cli/setup/chart.go b/pkg/cli/setup/chart.go index 93447a6e5b..40a6b1d973 100644 --- a/pkg/cli/setup/chart.go +++ b/pkg/cli/setup/chart.go @@ -32,7 +32,7 @@ type ChartArgs struct { UcpTag string // PublicEndpointOverride is used to define the public endpoint of the Kubernetes cluster - // for display purposes. This is useful when the the actual public IP address of a cluster's ingress + // for display purposes. This is useful when the actual public IP address of a cluster's ingress // is not a routable IP. This comes up all of the time for a local cluster. PublicEndpointOverride string diff --git a/pkg/ucp/store/apiserverstore/apiserverclient_test.go b/pkg/ucp/store/apiserverstore/apiserverclient_test.go index 1a33420c2b..d7e08a322c 100644 --- a/pkg/ucp/store/apiserverstore/apiserverclient_test.go +++ b/pkg/ucp/store/apiserverstore/apiserverclient_test.go @@ -105,7 +105,7 @@ func Test_ResourceName_Normalize(t *testing.T) { func Test_APIServer_Client(t *testing.T) { // The APIServer tests require installation of the Kubernetes test environment binaries. - // Our Makefile knows how to download the the amd64 version of these on MacOS. + // Our Makefile knows how to download the amd64 version of these on MacOS. rc, env, err := kubeenv.StartEnvironment([]string{filepath.Join("..", "..", "..", "..", "deploy", "Chart", "crds", "ucpd")}) require.NoError(t, err, "If this step is failing for you, run `make test` inside the repository and try again. If you are still stuck then ask for help.")