github.com/pulumi/pulumi-kubernetes/sdk/v3@v3.30.2/go/kubernetes/helm/v3/chart.go (about) 1 // Copyright 2016-2021, Pulumi Corporation. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // *** WARNING: this file was generated by pulumigen. *** 16 // *** Do not edit by hand unless you're certain you know what you are doing! *** 17 18 package helm 19 20 import ( 21 "encoding/json" 22 "fmt" 23 24 "github.com/pkg/errors" 25 "github.com/pulumi/pulumi-kubernetes/sdk/v3/go/kubernetes/yaml" 26 "github.com/pulumi/pulumi/sdk/v3/go/pulumi" 27 ) 28 29 // Chart is a component representing a collection of resources described by an arbitrary Helm 30 // Chart. The Chart can be fetched from any source that is accessible to the `helm` command 31 // line. Values in the `values.yml` file can be overridden using `ChartOpts.values` (equivalent 32 // to `--set` or having multiple `values.yml` files). Objects can be transformed arbitrarily by 33 // supplying callbacks to `ChartOpts.transformations`. 34 // 35 // `Chart` does not use Tiller. The Chart specified is copied and expanded locally; the semantics 36 // are equivalent to running `helm template` and then using Pulumi to manage the resulting YAML 37 // manifests. Any values that would be retrieved in-cluster are assigned fake values, and 38 // none of Tiller's server-side validity testing is executed. 39 // 40 // ## Example Usage 41 // ### Local Chart Directory 42 // 43 // ```go 44 // package main 45 // 46 // import ( 47 // 48 // "github.com/pulumi/pulumi-kubernetes/sdk/v3/go/kubernetes/helm/v3" 49 // "github.com/pulumi/pulumi/sdk/v3/go/pulumi" 50 // 51 // ) 52 // 53 // func main() { 54 // pulumi.Run(func(ctx *pulumi.Context) error { 55 // _, err := helm.NewChart(ctx, "nginx-ingress", helm.ChartArgs{ 56 // Path: pulumi.String("./nginx-ingress"), 57 // }) 58 // if err != nil { 59 // return err 60 // } 61 // 62 // return nil 63 // }) 64 // } 65 // 66 // ``` 67 // ### Remote Chart 68 // 69 // ```go 70 // package main 71 // 72 // import ( 73 // 74 // "github.com/pulumi/pulumi-kubernetes/sdk/v3/go/kubernetes/helm/v3" 75 // "github.com/pulumi/pulumi/sdk/v3/go/pulumi" 76 // 77 // ) 78 // 79 // func main() { 80 // pulumi.Run(func(ctx *pulumi.Context) error { 81 // _, err := helm.NewChart(ctx, "nginx-ingress", helm.ChartArgs{ 82 // Chart: pulumi.String("nginx-ingress"), 83 // Version: pulumi.String("1.24.4"), 84 // FetchArgs: helm.FetchArgs{ 85 // Repo: pulumi.String("https://charts.helm.sh/stable"), 86 // }, 87 // }) 88 // if err != nil { 89 // return err 90 // } 91 // 92 // return nil 93 // }) 94 // } 95 // 96 // ``` 97 // ### Set Chart values 98 // 99 // ```go 100 // package main 101 // 102 // import ( 103 // 104 // "github.com/pulumi/pulumi-kubernetes/sdk/v3/go/kubernetes/helm/v3" 105 // "github.com/pulumi/pulumi/sdk/v3/go/pulumi" 106 // 107 // ) 108 // 109 // func main() { 110 // pulumi.Run(func(ctx *pulumi.Context) error { 111 // _, err := helm.NewChart(ctx, "nginx-ingress", helm.ChartArgs{ 112 // Chart: pulumi.String("nginx-ingress"), 113 // Version: pulumi.String("1.24.4"), 114 // FetchArgs: helm.FetchArgs{ 115 // Repo: pulumi.String("https://charts.helm.sh/stable"), 116 // }, 117 // Values: pulumi.Map{ 118 // "controller": pulumi.Map{ 119 // "metrics": pulumi.Map{ 120 // "enabled": pulumi.Bool(true), 121 // }, 122 // }, 123 // }, 124 // }) 125 // if err != nil { 126 // return err 127 // } 128 // 129 // return nil 130 // }) 131 // } 132 // 133 // ``` 134 // ### Deploy Chart into Namespace 135 // 136 // ```go 137 // package main 138 // 139 // import ( 140 // 141 // "github.com/pulumi/pulumi-kubernetes/sdk/v3/go/kubernetes/helm/v3" 142 // "github.com/pulumi/pulumi/sdk/v3/go/pulumi" 143 // 144 // ) 145 // 146 // func main() { 147 // pulumi.Run(func(ctx *pulumi.Context) error { 148 // _, err := helm.NewChart(ctx, "nginx-ingress", helm.ChartArgs{ 149 // Chart: pulumi.String("nginx-ingress"), 150 // Version: pulumi.String("1.24.4"), 151 // Namespace: pulumi.String("test-namespace"), 152 // FetchArgs: helm.FetchArgs{ 153 // Repo: pulumi.String("https://charts.helm.sh/stable"), 154 // }, 155 // }) 156 // if err != nil { 157 // return err 158 // } 159 // 160 // return nil 161 // }) 162 // } 163 // 164 // ``` 165 // ### Chart with Transformations 166 // 167 // ```go 168 // package main 169 // 170 // import ( 171 // 172 // "github.com/pulumi/pulumi-kubernetes/sdk/v3/go/kubernetes/helm/v3" 173 // "github.com/pulumi/pulumi-kubernetes/sdk/v3/go/kubernetes/yaml" 174 // "github.com/pulumi/pulumi/sdk/v3/go/pulumi" 175 // 176 // ) 177 // 178 // func main() { 179 // pulumi.Run(func(ctx *pulumi.Context) error { 180 // _, err := helm.NewChart(ctx, "nginx-ingress", helm.ChartArgs{ 181 // Chart: pulumi.String("nginx-ingress"), 182 // Version: pulumi.String("1.24.4"), 183 // FetchArgs: helm.FetchArgs{ 184 // Repo: pulumi.String("https://charts.helm.sh/stable"), 185 // }, 186 // Transformations: []yaml.Transformation{ 187 // // Make every service private to the cluster, i.e., turn all services into ClusterIP 188 // // instead of LoadBalancer. 189 // func(state map[string]interface{}, opts ...pulumi.ResourceOption) { 190 // if state["kind"] == "Service" { 191 // spec := state["spec"].(map[string]interface{}) 192 // spec["type"] = "ClusterIP" 193 // } 194 // }, 195 // 196 // // Set a resource alias for a previous name. 197 // func(state map[string]interface{}, opts ...pulumi.ResourceOption) { 198 // if state["kind"] == "Deployment" { 199 // aliases := pulumi.Aliases([]pulumi.Alias{ 200 // { 201 // Name: pulumi.String("oldName"), 202 // }, 203 // }) 204 // opts = append(opts, aliases) 205 // } 206 // }, 207 // 208 // // Omit a resource from the Chart by transforming the specified resource definition 209 // // to an empty List. 210 // func(state map[string]interface{}, opts ...pulumi.ResourceOption) { 211 // name := state["metadata"].(map[string]interface{})["name"] 212 // if state["kind"] == "Pod" && name == "test" { 213 // state["apiVersion"] = "v1" 214 // state["kind"] = "List" 215 // } 216 // }, 217 // }, 218 // }) 219 // if err != nil { 220 // return err 221 // } 222 // 223 // return nil 224 // }) 225 // } 226 // 227 // ``` 228 type Chart struct { 229 pulumi.ResourceState 230 231 Ready pulumi.ResourceArrayOutput 232 Resources pulumi.Output 233 } 234 235 // NewChart registers a new resource with the given unique name, arguments, and options. 236 func NewChart(ctx *pulumi.Context, 237 name string, args ChartArgs, opts ...pulumi.ResourceOption) (*Chart, error) { 238 239 // Register the resulting resource state. 240 chart := &Chart{} 241 aliases := pulumi.Aliases([]pulumi.Alias{ 242 { 243 Type: pulumi.String("kubernetes:helm.sh/v2:Chart"), 244 }, 245 }) 246 247 var resourceOrInvokeOptions []pulumi.ResourceOrInvokeOption 248 for _, o := range opts { 249 if asResOrInv, ok := o.(pulumi.ResourceOrInvokeOption); ok { 250 resourceOrInvokeOptions = append(resourceOrInvokeOptions, asResOrInv) 251 } 252 } 253 opts = append(opts, aliases) 254 err := ctx.RegisterComponentResource("kubernetes:helm.sh/v3:Chart", name, chart, opts...) 255 if err != nil { 256 return nil, err 257 } 258 259 // Honor the resource name prefix if specified. 260 if args.ResourcePrefix != "" { 261 name = args.ResourcePrefix + "-" + name 262 } 263 264 resourceOrInvokeOptions = append(resourceOrInvokeOptions, pulumi.Parent(chart)) 265 resources := args.ToChartArgsOutput().ApplyT(func(args chartArgs) (map[string]pulumi.Resource, error) { 266 return parseChart(ctx, name, args, resourceOrInvokeOptions...) 267 }) 268 chart.Resources = resources 269 270 // Finally, register all of the resources found. 271 // Note: Go requires that we "pull" on our futures in order to get them scheduled for execution. Here, we use 272 // the engine's RegisterResourceOutputs to wait for the resolution of all resources that this Helm chart created. 273 err = ctx.RegisterResourceOutputs(chart, pulumi.Map{"resources": resources}) 274 if err != nil { 275 return nil, errors.Wrap(err, "registering child resources") 276 } 277 278 chart.Ready = resources.ApplyT(func(x interface{}) []pulumi.Resource { 279 resources := x.(map[string]pulumi.Resource) 280 var outputs []pulumi.Resource 281 for _, r := range resources { 282 outputs = append(outputs, r) 283 } 284 return outputs 285 }).(pulumi.ResourceArrayOutput) 286 287 return chart, nil 288 } 289 290 func parseChart(ctx *pulumi.Context, name string, args chartArgs, opts ...pulumi.ResourceOrInvokeOption, 291 ) (map[string]pulumi.Resource, error) { 292 type jsonOptsArgs struct { 293 chartArgs 294 295 ReleaseName string `json:"release_name,omitempty"` 296 } 297 jsonOpts := jsonOptsArgs{ 298 chartArgs: args, 299 ReleaseName: name, 300 } 301 302 b, err := json.Marshal(jsonOpts) 303 if err != nil { 304 return nil, err 305 } 306 307 var invokeOpts []pulumi.InvokeOption 308 var resourceOpts []pulumi.ResourceOption 309 for _, o := range opts { 310 invokeOpts = append(invokeOpts, o) 311 resourceOpts = append(resourceOpts, o) 312 } 313 objs, err := helmTemplate(ctx, string(b), invokeOpts...) 314 if err != nil { 315 return nil, err 316 } 317 318 transformations := args.Transformations 319 if args.SkipAwait { 320 transformations = yaml.AddSkipAwaitTransformation(transformations) 321 } 322 323 resources, err := yaml.ParseYamlObjects(ctx, objs, transformations, args.ResourcePrefix, resourceOpts...) 324 if err != nil { 325 return nil, err 326 } 327 return resources, nil 328 } 329 330 // helmTemplate invokes the function to fetch and template a Helm Chart and decompose it into object structures. 331 func helmTemplate( 332 ctx *pulumi.Context, jsonOpts string, opts ...pulumi.InvokeOption, 333 ) ([]map[string]interface{}, error) { 334 args := struct { 335 JsonOpts string `pulumi:"jsonOpts"` 336 }{JsonOpts: jsonOpts} 337 var ret struct { 338 Result []map[string]interface{} `pulumi:"result"` 339 } 340 341 if err := ctx.Invoke("kubernetes:helm:template", &args, &ret, opts...); err != nil { 342 return nil, errors.Wrap(err, "failed to invoke helm template") 343 } 344 return ret.Result, nil 345 } 346 347 // GetResource returns a resource defined by a built-in Kubernetes group/version/kind, name and namespace. 348 // For example, GetResource("v1/Pod", "foo", "") would return a Pod called "foo" from the "default" namespace. 349 func (c *Chart) GetResource(gvk, name, namespace string) pulumi.AnyOutput { 350 id := name 351 if len(namespace) > 0 && namespace != "default" { 352 id = fmt.Sprintf("%s/%s", namespace, name) 353 } 354 key := fmt.Sprintf("%s::%s", gvk, id) 355 return c.Resources.ApplyT(func(x interface{}) interface{} { 356 resources := x.(map[string]pulumi.Resource) 357 return resources[key] 358 }).(pulumi.AnyOutput) 359 }