Sep. 16 releases: Helm Release, pulumi about, easier invites
Posted on
It’s been a busy few weeks at Pulumi, including for some of our community contributors! Read on to see what’s new.
- New and updated cloud providers
- Pulumi CLI and core technologies
- Pulumi Service and Pulumi.com
New and updated cloud providers
New Helm Release resource for Kubernetes
Pulumi’s existing Helm Chart
resource provides support for deploying Helm charts via templating the chart and deploying it as Pulumi resources. This means that some features of Helm that are not availabe via Helm templating do not behave quite the same using the Pulumi Helm Chart
resource as they do when deployed via the helm
CLI itself - for example features like Helm lifecycle hooks and handling sub-charts and dependencies. As Helm and its usage evolved over the years, Pulumi users using the Chart
resource have noted that in many cases they would like a resource that provides the exact same behave as the helm
CLI, but can be orchestrated as part of a Pulumi deployment.
The new Helm Release
resource provides Pulumi users more options to choose the right tool for their use-case. In contrast to the existing Helm Chart
integration, which is implemented as a Component Resource that extracts the corresponding Kubernetes resources’ manifests from the chart and installs them as if they were individually specified in the Pulumi user program, the new Helm Release
resource uses the Helm SDK directly to perform the deployment, providing the exact same behavior as a corresponding helm
CLI deployment.
You can get started with the Helm Release resource in versions v3.7.0 and higher of the Pulumi Kubernetes Provider and SDK in all Pulumi supported languages.For example, in the following snippet we install Redis through a Helm Chart:
import * as random from "@pulumi/random";
import * as pulumi from "@pulumi/pulumi";
import * as k8s from "@pulumi/kubernetes";
// Create a password
const pass = new random.RandomPassword("pass", {length:10});
const redisPassword = pass.result;
const namespace = new k8s.core.v1.Namespace("redis-ns");
const release = new k8s.helm.v3.Release("redis-helm", {
chart: "redis",
repositoryOpts: {
repo: "https://charts.bitnami.com/bitnami",
},
version: "13.0.0",
namespace: namespace.metadata.name,
// Values from Chart's parameters specified hierarchically,
// see https://artifacthub.io/packages/helm/bitnami/redis/13.0.0#parameters for reference.
values: {
cluster: {
enabled: true,
slaveCount: 3,
},
metrics: {
enabled: true,
service: {
annotations: {
"prometheus.io/port": "9127",
}
},
},
global: {
redis: {
password: redisPassword,
}
},
rbac: {
create: true,
}
},
// By default Release resource will wait till all created resources
// are available. Set this to true to skip waiting on resources being
// available.
skipAwait: false,
});
// We can lookup resources once the release is installed. The release's
// status field is set once the installation completes, so this, combined
// with `skipAwait: false` above, will wait to retrieve the Redis master
// ClusterIP till all resources in the Chart are available.
const srv = k8s.core.v1.Service.get("redis-master-svc",
pulumi.interpolate`${release.status.namespace}/${release.status.name}-redis-master`);
export const redisMasterClusterIP = srv.spec.clusterIP;
package main
import (
"fmt"
corev1 "github.com/pulumi/pulumi-kubernetes/sdk/v3/go/kubernetes/core/v1"
"github.com/pulumi/pulumi-kubernetes/sdk/v3/go/kubernetes/helm/v3"
"github.com/pulumi/pulumi-random/sdk/v4/go/random"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
namespace, err := corev1.NewNamespace(ctx, "redis-ns", nil)
if err != nil {
return err
}
redisPassword, err := random.NewRandomPassword(ctx, "pass", &random.RandomPasswordArgs{
Length: pulumi.Int(10),
})
if err != nil {
return err
}
rel, err := helm.NewRelease(ctx, "redis-helm", &helm.ReleaseArgs{
Chart: pulumi.String("redis"),
RepositoryOpts: helm.RepositoryOptsArgs{
Repo: pulumi.String("https://charts.bitnami.com/bitnami"),
},
Version: pulumi.String("13.0.0"),
Namespace: namespace.Metadata.Name(),
// Values from Chart's parameters specified hierarchically,
// see https://artifacthub.io/packages/helm/bitnami/redis/13.0.0#parameters for reference.
Values: pulumi.Map{
"cluster": pulumi.Map{
"enabled": pulumi.Bool(true),
},
"metrics": pulumi.Map{
"enabled": pulumi.Bool(true),
"service": pulumi.Map{
"annotations": pulumi.StringMap{
"prometheus.io/port": pulumi.String("9127"),
},
"type": pulumi.String("ClusterIP"),
},
},
"global": pulumi.Map{
"redis": pulumi.Map{
"password": redisPassword.Result,
},
},
"rbac": pulumi.BoolMap{
"create": pulumi.Bool(true),
},
},
// By default Release resource will wait till all created resources
// are available. Set this to true to skip waiting on resources being
// available.
SkipAwait: pulumi.BoolPtr(false),
})
if err != nil {
return err
}
// We can lookup resources once the release is installed. The release's
// status field is set once the installation completes, so this, combined
// with `skipAwait: pulumi.BoolPtr(false)` above, will wait to retrieve
// the Redis master ClusterIP till all resources in the Chart are available.
svc := pulumi.All(rel.Status.Namespace(), rel.Status.Name()).
ApplyT(func(r interface{}) (interface{}, error) {
arr := r.([]interface{})
namespace := arr[0].(*string)
name := arr[1].(*string)
svc, err := corev1.GetService(ctx,
"redis-master-svc",
pulumi.ID(fmt.Sprintf("%s/%s-redis-master", *namespace, *name)),
nil,
)
if err != nil {
return "", nil
}
return svc.Spec.ClusterIP(), nil
})
ctx.Export("redisMasterClusterIP", svc)
return nil
})
}
import pulumi
from pulumi import Output
from pulumi_random.random_password import RandomPassword
from pulumi_kubernetes.core.v1 import Namespace, Service
from pulumi_kubernetes.helm.v3 import Release, ReleaseArgs, RepositoryOptsArgs
namespace = Namespace("redis-ns")
redis_password = RandomPassword("pass", length=10)
release_args = ReleaseArgs(
chart="redis",
repository_opts=RepositoryOptsArgs(
repo="https://charts.bitnami.com/bitnami"
),
version="13.0.0",
namespace=namespace.metadata["name"],
# Values from Chart's parameters specified hierarchically,
# see https://artifacthub.io/packages/helm/bitnami/redis/13.0.0#parameters
# for reference.
values={
"cluster": {
"enabled": True,
"slaveCount": 3,
},
"metrics": {
"enabled": True,
"service": {
"annotations": {
"prometheus.io/port": "9127",
}
},
},
"global": {
"redis": {
"password": redis_password.result,
}
},
"rbac": {
"create": True,
},
},
# By default Release resource will wait till all created resources
# are available. Set this to true to skip waiting on resources being
# available.
skip_await=False)
release = Release("redis-helm", args=release_args)
# We can lookup resources once the release is installed. The release's
# status field is set once the installation completes, so this, combined
# with `skip_await=False` above, will wait to retrieve the Redis master
# ClusterIP till all resources in the Chart are available.
status = release.status
srv = Service.get("redis-master-svc",
Output.concat(status.namespace, "/", status.name, "-redis-master"))
pulumi.export("redisMasterClusterIP", srv.spec.cluster_ip)
using Pulumi;
using System.Collections.Generic;
using Pulumi.Random;
using Pulumi.Kubernetes.Core.V1;
using Pulumi.Kubernetes.Types.Inputs.Helm.V3;
using Pulumi.Kubernetes.Helm.V3;
class MyStack : Stack
{
public MyStack()
{
var ns = new Pulumi.Kubernetes.Core.V1.Namespace("redis-ns");
var redisPassword = new RandomPassword("pass", new RandomPasswordArgs
{
Length = 10,
});
var releaseArgs = new ReleaseArgs
{
Chart = "redis",
RepositoryOpts = new RepositoryOptsArgs
{
Repo = "https://charts.bitnami.com/bitnami",
},
Version = "13.0.0",
Namespace = ns.Metadata.Apply(metadata => metadata.Name),
// Values from Chart's parameters specified hierarchically,
// see https://artifacthub.io/packages/helm/bitnami/redis/13.0.0#parameters
// for reference.
Values = new InputMap<object>
{
["cluster"] = new Dictionary<string,object>
{
["enabled"] = true,
["slaveCount"] = 3,
},
["metrics"] = new Dictionary<string,object>
{
["enabled"] = true,
["service"] = new Dictionary<string, object>
{
["annotations"] = new Dictionary<string, string>
{
["prometheus.io/port"] = "9127",
},
}
},
["global"] = new Dictionary<string,object>
{
["redis"] = new Dictionary<string, object>
{
["password"] = redisPassword.Result,
},
},
["rbac"] = new Dictionary<string,object>
{
["create"] = true,
}
},
// By default Release resource will wait till all created resources
// are available. Set this to true to skip waiting on resources being
// available.
SkipAwait = false,
};
var release = new Release("redis-helm", releaseArgs);
// We can lookup resources once the release is installed. The release's
// status field is set once the installation completes, so this, combined
// with `skip_await=False` above, will wait to retrieve the Redis master
// ClusterIP till all resources in the Chart are available.
var status = release.Status;
var service = Service.Get("redist-master-svc", Output.All(status).Apply(
s => $"{s[0].Namespace}/{s[0].Name}-redis-master"));
this.RedisMasterClusterIP = service.Spec.Apply(spec => spec.ClusterIP);
}
[Output]
public Output<string> RedisMasterClusterIP { get; set; }
}
Learn more in the announcement blog post
New providers: MinIO and Snowflake
You can now use Pulumi’s modern infrastructure-as-code solution to manage new resources! Our new provider for MinIO gives you access to the full range of high-performance, S3-compatible object storage offered by MinIO. Likewise, our new provider for Snowflake lets you create and manage many of the data engineering, data lake, data warehouse, and other data resources in Snowflake’s data cloud.
Learn more in the MinIO and Snowflake provider docs
New resources in the Azure Native provider
We shipped new versions of the Azure Native provider (1.22.0 through 1.28.0) that collectively added 15 new resources across services like SQL Server, Kusto, DocumentDB, and Power BI that you can now manage with the Azure Native provider.
Pulumi CLI and core technologies
In this milestone, we shipped Pulumi versions 3.10.2 through 3.12.0. The full list of changes in each version is available in the changelog; read on to learn about some of the biggest changes.
New pulumi about
command for easier troubleshooting
To make it easier to troubleshoot errors in the Pulumi CLI, we’ve added a new pulumi about
command that collects useful information like the plugins you have installed, the OS and architecture you’re running, the backend that’s storing your state, your CLI version, and more.
Learn more in this GitHub issue
pulumi config set
hides secret values
Previously, setting a config value using pulumi config set
would write the value to stdout
, which could be undesirable if the config value was a secret. Now, config values that look like secrets will be hidden and the config key name will be written to stdout
instead.
Thanks @JasonWhall for contributing this change!
Dynamic providers in Python can now given a custom name
When building a dynamic provider, it can be useful to give the provider a name so that at runtime, you can identify which provider is actually making a change. Previously, it wasn’t possible to do so in Python. Now, you can pass a name
parameter to the dynamic provider’s constructor:
class CustomResource(
Resource, module="custom-provider", name="CustomResource"
):
...
Thanks @jancespivo for contributing this change!
Learn more in this GitHub issue
Automation API in .NET can use plugin installation options exact
and server
When running Pulumi interactively, you can use the pulumi plugin install
command to manually install plugins required by your program, possibly from a server where you host your own plugins. You can now do the same task in the .NET Automation API:
await workspace.InstallPluginAsync("myplugin", "v0.0.1", options: new PluginInstallOptions
{
ServerUrl = "https://<custom-url>",
});
Thanks @orionstudt for contributing this change!
Schema checker for Pulumi Packages
When authoring a Pulumi Package, it can be helpful to validate that your schema is correct. Now, you can validate your schema by running the pulumi schema check
command.
Pulumi Service and Pulumi.com
Organization invites now send you to the correct identity provider
Previously, when you invited a collaborator to your organization, that collaborator needed to know which identity provider (email, GitHub, GitLab, Bitbucket, or SAML SSO) that your organization uses in order to sign up correctly and get access to the organization. Now, any invites you send will direct your new collaborator to the correct identity provider automatically.