-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feat: Add both Azure and local-dev object-store recipes
Signed-off-by: SoTrx <11771975+SoTrx@users.noreply.github.com>
- Loading branch information
Showing
2 changed files
with
359 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
extension kubernetes with { | ||
kubeConfig: '' | ||
namespace: context.runtime.kubernetes.namespace | ||
} as k8s | ||
extension radius | ||
|
||
@description('Information about what resource is calling this Recipe. Generated by Radius. For more information visit https://docs.radapp.dev/operations/custom-recipes/') | ||
param context object | ||
|
||
@description('Name of the storage account to use') | ||
param accountName string | ||
|
||
@description('Optional storage account key as a secret reference to a Dapr secret store. If this is not provided, either the worload identity will be used or the account key will be fetched from the storage account reference.') | ||
param accountKeyRef SecretStoreReference = { | ||
secretStoreName: '' | ||
secretKeyRef: { | ||
name: 'accountKey' | ||
key: 'accountKey' | ||
} | ||
} | ||
|
||
@description('Wether to use workload identity to access the storage account. Default is false') | ||
param useWorkloadIdentity bool = false | ||
|
||
@description('Name of the bucket to create in the S3-compatible object store. Default is mybucket') | ||
param bucket string = 'mybucket' | ||
|
||
@description('Encode binary files content in base64 before sending it to the application. Default is true') | ||
param decodeBase64 bool = true | ||
|
||
|
||
|
||
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' existing = { | ||
name: accountName | ||
} | ||
|
||
var accountKeyMetadata = useWorkloadIdentity | ||
// If workload identity is used, the account key is not needed. | ||
? {} | ||
// If workload identity is not used, the account key can be provided as a secret or a value. | ||
// As a secret, the secret store name must be provided. | ||
: !empty(accountKeyRef.secretStoreName) | ||
? { | ||
name: 'accountKey' | ||
secretKeyRef: accountKeyRef.secretKeyRef | ||
} | ||
// As a value, the account key can be fetched from the storage account reference. | ||
: { | ||
name: 'accountKey' | ||
value: storageAccount.listKeys().keys[0].value | ||
} | ||
|
||
// The secret store name is only needed if the account key is provided as a secret. | ||
var daprAuthProperty = !empty(accountKeyRef.secretKeyRef) | ||
? { secretStore: accountKeyRef.secretStoreName } | ||
: { secretStore: '' } | ||
|
||
|
||
var daprType = 'bindings.azure.blobstorage' | ||
var daprVersion = 'v1' | ||
resource daprComponent 'dapr.io/Component@v1alpha1' = { | ||
auth: daprAuthProperty | ||
metadata: { | ||
name: context.resource.name | ||
} | ||
spec: { | ||
type: daprType | ||
version: daprVersion | ||
metadata: concat( | ||
[ | ||
{ | ||
name: 'accountName' | ||
value: storageAccount.name | ||
} | ||
{ | ||
name: 'containerName' | ||
value: bucket | ||
} | ||
{ | ||
name: 'decodeBase64' | ||
value: decodeBase64 | ||
} | ||
], | ||
[accountKeyMetadata] | ||
) | ||
} | ||
} | ||
|
||
@description('Reference to a secret in a Dapr secret store') | ||
type SecretStoreReference = { | ||
@description('Name of the secret store') | ||
secretStoreName: string | ||
@description('Reference to a key in the secret store') | ||
secretKeyRef: { | ||
@description('Name of the secret') | ||
name: string | ||
@description('Key of the secret if it is a dictionary') | ||
key: string | ||
} | ||
} | ||
|
||
output result object = { | ||
// This workaround is needed because the deployment engine omits Kubernetes resources from its output. | ||
// This allows Kubernetes resources to be cleaned up when the resource is deleted. | ||
// Once this gap is addressed, users won't need to do this. | ||
resources: [ | ||
'/planes/kubernetes/local/namespaces/${daprComponent.metadata.namespace}/providers/dapr.io/Component/${daprComponent.metadata.name}' | ||
] | ||
values: { | ||
type: daprType | ||
version: daprVersion | ||
metadata: daprComponent.spec.metadata | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,245 @@ | ||
/* | ||
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. | ||
*/ | ||
@description('Information about what resource is calling this Recipe. Generated by Radius. For more information visit https://docs.radapp.dev/operations/custom-recipes/') | ||
param context object | ||
|
||
@description('Name of the bucket to create in the S3-compatible object store') | ||
param bucket string = 'mybucket' | ||
|
||
@description('Tag to pull for the minio container image.') | ||
param tag string = 'latest' | ||
|
||
@description('Default admin username for the MinIO object store') | ||
param minioUser string = 'minioadmin' | ||
|
||
@secure() | ||
@description('Default admin password for the MinIO object store') | ||
#disable-next-line secure-parameter-default | ||
param minioPassword string = 'minioadmin' | ||
|
||
@description('Port for the MinIO object store S3-like API') | ||
param minioApiPort int = 9000 | ||
|
||
@description('Port for the MinIO object store Web UI') | ||
param minioWebPort int = 9001 | ||
|
||
@description('Binary files must be converted base64 before being sent to the object store') | ||
param encodeBase64 bool = true | ||
|
||
@description('Encode binary files content in base64 before sending it to the application') | ||
param decodeBase64 bool = true | ||
|
||
|
||
extension kubernetes with { | ||
kubeConfig: '' | ||
namespace: context.runtime.kubernetes.namespace | ||
} as kubernetes | ||
|
||
var uniqueName = 'daprbindingobj-${uniqueString(context.resource.id)}' | ||
|
||
resource minio 'apps/Deployment@v1' = { | ||
metadata: { | ||
name: uniqueName | ||
} | ||
spec: { | ||
replicas: 1 | ||
selector: { | ||
matchLabels: { | ||
app: 'minio-app' | ||
resource: context.resource.name | ||
} | ||
} | ||
template: { | ||
metadata: { | ||
labels: { | ||
app: 'minio-app' | ||
resource: context.resource.name | ||
'radapp.io/application': context.application == null ? '' : context.application.name | ||
} | ||
} | ||
spec: { | ||
// This initContainer creates the bucket in the MinIO object store | ||
// This works because the MinIO container is configured to use an emptyDir volume | ||
// So in this case a bucket is a directory | ||
initContainers: [ | ||
{ | ||
name: 'bucket-creation' | ||
image: 'busybox:1.28' | ||
command: [ | ||
'/bin/sh', '-c' | ||
'echo "Creating bucket ${bucket}" && mkdir -p /data/${bucket}' | ||
] | ||
volumeMounts: [ | ||
{ | ||
name: 'data' | ||
mountPath: '/data' | ||
} | ||
] | ||
} | ||
] | ||
containers: [ | ||
{ | ||
name: 'minio' | ||
image: 'minio/minio:${tag}' | ||
args: [ | ||
'server' | ||
'--address' | ||
':${minioApiPort}' | ||
// Console address refers to the Web UI, somehow | ||
'--console-address' | ||
':${minioWebPort}' | ||
'/data' | ||
] | ||
ports: [ | ||
{ containerPort: minioApiPort } | ||
{ containerPort: minioWebPort } | ||
] | ||
env: [ | ||
{ | ||
name: 'MINIO_ROOT_USER' | ||
value: minioUser | ||
} | ||
{ | ||
name: 'MINIO_ROOT_PASSWORD' | ||
value: minioPassword | ||
} | ||
// The browser animation will break port-forwarding | ||
// https://github.com/minio/console/issues/2539 | ||
{ | ||
name: 'MINIO_BROWSER_LOGIN_ANIMATION' | ||
value: 'off' | ||
} | ||
] | ||
volumeMounts: [ | ||
{ | ||
name: 'data' | ||
mountPath: '/data' | ||
} | ||
] | ||
} | ||
] | ||
volumes: [ | ||
{ | ||
name: 'data' | ||
emptyDir: {} // In-memory storage, not persistent (for dev/test) | ||
} | ||
] | ||
} | ||
} | ||
} | ||
} | ||
|
||
resource svc 'core/Service@v1' = { | ||
metadata: { | ||
name: uniqueName | ||
} | ||
spec: { | ||
type: 'ClusterIP' | ||
selector: { | ||
app: 'minio-app' | ||
resource: context.resource.name | ||
} | ||
ports: [ | ||
{ | ||
name: 'api' | ||
port: minioApiPort | ||
targetPort: minioApiPort | ||
} | ||
{ | ||
name: 'ui' | ||
port: minioWebPort | ||
targetPort: minioWebPort | ||
} | ||
] | ||
} | ||
} | ||
|
||
|
||
|
||
var daprType = 'bindings.aws.s3' | ||
var daprVersion = 'v1' | ||
resource daprComponent 'dapr.io/Component@v1alpha1' = { | ||
metadata: { | ||
name: context.resource.name | ||
} | ||
spec: { | ||
type: daprType | ||
version: daprVersion | ||
metadata: [ | ||
{ | ||
name: 'endpoint' | ||
value: '${svc.metadata.name}.${svc.metadata.namespace}.svc.cluster.local:${minioApiPort}' | ||
} | ||
{ | ||
name: 'bucket' | ||
value: bucket | ||
} | ||
// The admin credentials are used by the Dapr sidecar to access the object store | ||
// In a production scenario, another user with fewer permissions should be used | ||
{ | ||
name: 'accessKey' | ||
value: minioUser | ||
} | ||
{ | ||
name: 'secretKey' | ||
value: minioPassword | ||
} | ||
// Binary files must be converted to base64 to be handled by Dapr | ||
// This adds some overhead, so it can be disabled if not needed | ||
{ | ||
name: 'encodeBase64' | ||
value: encodeBase64 ? 'true' : 'false' | ||
} | ||
{ | ||
name: 'decodeBase64' | ||
value: decodeBase64 ? 'true' : 'false' | ||
} | ||
// The next three values are recommended for MinIO by the documentation | ||
// https://docs.dapr.io/reference/components-reference/supported-bindings/s3/#s3-bucket-creation | ||
{ | ||
name: 'region' | ||
value: 'us-east-1' // Some old Dapr versions require this to be set | ||
} | ||
|
||
{ | ||
name: 'forcePathStyle' | ||
value: true | ||
} | ||
|
||
{ | ||
name: 'disableSSL' | ||
value: true | ||
} | ||
] | ||
} | ||
} | ||
|
||
output result object = { | ||
// This workaround is needed because the deployment engine omits Kubernetes resources from its output. | ||
// This allows Kubernetes resources to be cleaned up when the resource is deleted. | ||
// Once this gap is addressed, users won't need to do this. | ||
resources: [ | ||
'/planes/kubernetes/local/namespaces/${svc.metadata.namespace}/providers/core/Service/${svc.metadata.name}' | ||
'/planes/kubernetes/local/namespaces/${minio.metadata.namespace}/providers/apps/Deployment/${minio.metadata.name}' | ||
'/planes/kubernetes/local/namespaces/${daprComponent.metadata.namespace}/providers/dapr.io/Component/${daprComponent.metadata.name}' | ||
] | ||
values: { | ||
type: daprType | ||
version: daprVersion | ||
metadata: daprComponent.spec.metadata | ||
} | ||
} | ||
|