2022-09-05 03:06:08 -04:00
/ *
Copyright ( c ) Edgeless Systems GmbH
SPDX - License - Identifier : AGPL - 3.0 - only
* /
2022-08-12 04:20:19 -04:00
package helm
import (
"bytes"
"embed"
2022-10-21 06:01:28 -04:00
"encoding/base64"
2022-08-12 04:20:19 -04:00
"encoding/json"
"fmt"
"io/fs"
2022-10-21 06:01:28 -04:00
"os"
2022-08-12 04:20:19 -04:00
"path/filepath"
"strings"
2023-05-02 03:35:52 -04:00
"github.com/pkg/errors"
"helm.sh/helm/pkg/ignore"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/chartutil"
2023-04-03 12:09:03 -04:00
"github.com/edgelesssys/constellation/v2/cli/internal/helm/imageversion"
2022-09-21 07:47:57 -04:00
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
2023-01-31 06:12:19 -05:00
"github.com/edgelesssys/constellation/v2/internal/compatibility"
2022-11-18 04:05:02 -05:00
"github.com/edgelesssys/constellation/v2/internal/config"
2022-10-18 07:15:54 -04:00
"github.com/edgelesssys/constellation/v2/internal/constants"
2022-09-21 07:47:57 -04:00
"github.com/edgelesssys/constellation/v2/internal/deploy/helm"
2022-10-18 07:15:54 -04:00
"github.com/edgelesssys/constellation/v2/internal/versions"
2022-08-12 04:20:19 -04:00
)
2022-11-21 04:35:40 -05:00
// Run `go generate` to download (and patch) upstream helm charts.
2022-08-12 04:20:19 -04:00
//go:generate ./generateCilium.sh
2022-11-18 04:05:02 -05:00
//go:generate ./update-csi-charts.sh
2022-11-21 04:35:40 -05:00
//go:generate ./generateCertManager.sh
2023-07-24 04:30:53 -04:00
//go:generate ./update-aws-load-balancer-chart.sh
2022-08-12 04:20:19 -04:00
2022-10-18 07:15:54 -04:00
//go:embed all:charts/*
2022-11-09 09:57:54 -05:00
var helmFS embed . FS
2022-08-12 04:20:19 -04:00
2023-03-20 09:49:04 -04:00
type chartInfo struct {
releaseName string
chartName string
path string
}
var (
ciliumInfo = chartInfo { releaseName : "cilium" , chartName : "cilium" , path : "charts/cilium" }
certManagerInfo = chartInfo { releaseName : "cert-manager" , chartName : "cert-manager" , path : "charts/cert-manager" }
constellationOperatorsInfo = chartInfo { releaseName : "constellation-operators" , chartName : "constellation-operators" , path : "charts/edgeless/operators" }
constellationServicesInfo = chartInfo { releaseName : "constellation-services" , chartName : "constellation-services" , path : "charts/edgeless/constellation-services" }
2023-07-24 04:30:53 -04:00
awsLBControllerInfo = chartInfo { releaseName : "aws-load-balancer-controller" , chartName : "aws-load-balancer-controller" , path : "charts/aws-load-balancer-controller" }
2023-06-26 04:13:28 -04:00
csiInfo = chartInfo { releaseName : "constellation-csi" , chartName : "constellation-csi" , path : "charts/edgeless/csi" }
2022-12-19 10:52:15 -05:00
)
2022-11-09 09:57:54 -05:00
// ChartLoader loads embedded helm charts.
2022-10-31 14:25:02 -04:00
type ChartLoader struct {
2023-02-14 12:00:36 -05:00
csp cloudprovider . Provider
2022-11-28 03:15:39 -05:00
joinServiceImage string
2023-01-20 12:51:06 -05:00
keyServiceImage string
2023-07-24 04:30:53 -04:00
ccmImage string // cloud controller manager image
azureCNMImage string // Azure cloud node manager image
2022-11-28 03:15:39 -05:00
autoscalerImage string
verificationServiceImage string
gcpGuestAgentImage string
konnectivityImage string
constellationOperatorImage string
nodeMaintenanceOperatorImage string
2023-07-24 04:30:53 -04:00
clusterName string
2022-11-21 11:06:41 -05:00
}
2022-11-24 10:39:33 -05:00
// NewLoader creates a new ChartLoader.
2023-07-24 04:30:53 -04:00
func NewLoader ( csp cloudprovider . Provider , k8sVersion versions . ValidK8sVersion , clusterName string ) * ChartLoader {
2022-11-02 12:47:10 -04:00
var ccmImage , cnmImage string
2022-10-31 14:25:02 -04:00
switch csp {
case cloudprovider . AWS :
ccmImage = versions . VersionConfigs [ k8sVersion ] . CloudControllerManagerImageAWS
case cloudprovider . Azure :
ccmImage = versions . VersionConfigs [ k8sVersion ] . CloudControllerManagerImageAzure
2022-11-02 12:47:10 -04:00
cnmImage = versions . VersionConfigs [ k8sVersion ] . CloudNodeManagerImageAzure
2022-10-31 14:25:02 -04:00
case cloudprovider . GCP :
ccmImage = versions . VersionConfigs [ k8sVersion ] . CloudControllerManagerImageGCP
2023-03-17 04:52:23 -04:00
case cloudprovider . OpenStack :
ccmImage = versions . VersionConfigs [ k8sVersion ] . CloudControllerManagerImageOpenStack
2022-10-31 14:25:02 -04:00
}
2022-08-12 04:20:19 -04:00
2023-04-03 12:09:03 -04:00
// TODO(malt3): Allow overriding container image registry + prefix for all images
// (e.g. for air-gapped environments).
2022-10-31 14:25:02 -04:00
return & ChartLoader {
2023-02-14 12:00:36 -05:00
csp : csp ,
2023-04-03 12:09:03 -04:00
joinServiceImage : imageversion . JoinService ( "" , "" ) ,
keyServiceImage : imageversion . KeyService ( "" , "" ) ,
2022-11-28 03:15:39 -05:00
ccmImage : ccmImage ,
2023-07-24 04:30:53 -04:00
azureCNMImage : cnmImage ,
2022-11-28 03:15:39 -05:00
autoscalerImage : versions . VersionConfigs [ k8sVersion ] . ClusterAutoscalerImage ,
2023-04-03 12:09:03 -04:00
verificationServiceImage : imageversion . VerificationService ( "" , "" ) ,
2022-11-28 03:15:39 -05:00
gcpGuestAgentImage : versions . GcpGuestImage ,
konnectivityImage : versions . KonnectivityAgentImage ,
2023-04-03 12:09:03 -04:00
constellationOperatorImage : imageversion . ConstellationNodeOperator ( "" , "" ) ,
2022-11-28 03:15:39 -05:00
nodeMaintenanceOperatorImage : versions . NodeMaintenanceOperatorImage ,
2023-07-24 04:30:53 -04:00
clusterName : clusterName ,
2022-10-31 14:25:02 -04:00
}
}
2022-11-09 09:57:54 -05:00
// Load the embedded helm charts.
2023-07-07 11:09:45 -04:00
func ( i * ChartLoader ) Load ( config * config . Config , conformanceMode bool , helmWaitMode helm . WaitMode , masterSecret , salt [ ] byte ) ( [ ] byte , error ) {
ciliumRelease , err := i . loadRelease ( ciliumInfo , helmWaitMode )
2022-08-12 04:20:19 -04:00
if err != nil {
2022-10-21 11:09:43 -04:00
return nil , fmt . Errorf ( "loading cilium: %w" , err )
2022-08-12 04:20:19 -04:00
}
2023-02-14 10:41:19 -05:00
extendCiliumValues ( ciliumRelease . Values , conformanceMode )
2022-10-18 07:15:54 -04:00
2023-07-07 11:09:45 -04:00
certManagerRelease , err := i . loadRelease ( certManagerInfo , helmWaitMode )
2022-11-21 04:35:40 -05:00
if err != nil {
2023-03-20 12:05:58 -04:00
return nil , fmt . Errorf ( "loading cert-manager: %w" , err )
2022-11-21 04:35:40 -05:00
}
2023-07-07 11:09:45 -04:00
operatorRelease , err := i . loadRelease ( constellationOperatorsInfo , helmWaitMode )
2022-11-21 04:35:40 -05:00
if err != nil {
return nil , fmt . Errorf ( "loading operators: %w" , err )
}
2023-07-07 11:09:45 -04:00
conServicesRelease , err := i . loadRelease ( constellationServicesInfo , helmWaitMode )
2022-08-12 04:20:19 -04:00
if err != nil {
2022-10-21 11:09:43 -04:00
return nil , fmt . Errorf ( "loading constellation-services: %w" , err )
2022-08-12 04:20:19 -04:00
}
2023-05-03 05:11:53 -04:00
if err := extendConstellationServicesValues ( conServicesRelease . Values , config , masterSecret , salt ) ; err != nil {
2023-02-14 10:41:19 -05:00
return nil , fmt . Errorf ( "extending constellation-services values: %w" , err )
}
2023-07-24 04:30:53 -04:00
releases := helm . Releases { Cilium : ciliumRelease , CertManager : certManagerRelease , ConstellationOperators : operatorRelease , ConstellationServices : conServicesRelease }
if config . HasProvider ( cloudprovider . AWS ) {
awsRelease , err := i . loadRelease ( awsLBControllerInfo , helmWaitMode )
if err != nil {
return nil , fmt . Errorf ( "loading aws-services: %w" , err )
}
releases . AWSLoadBalancerController = & awsRelease
}
2022-10-21 06:01:28 -04:00
2023-06-22 10:31:35 -04:00
if config . DeployCSIDriver ( ) {
2023-06-26 04:13:28 -04:00
csi , err := i . loadRelease ( csiInfo , helmWaitMode )
2023-06-22 10:31:35 -04:00
if err != nil {
return nil , fmt . Errorf ( "loading snapshot CRDs: %w" , err )
}
2023-06-26 04:13:28 -04:00
releases . CSI = & csi
2023-06-22 10:31:35 -04:00
}
2022-10-18 07:15:54 -04:00
rel , err := json . Marshal ( releases )
if err != nil {
return nil , err
}
return rel , nil
2022-08-12 04:20:19 -04:00
}
2023-03-20 12:05:58 -04:00
// loadRelease loads the embedded chart and values depending on the given info argument.
2023-07-24 04:30:53 -04:00
// IMPORTANT: .helmignore rules specifying files in subdirectories are not applied (e.g. crds/kustomization.yaml).
2023-07-07 11:09:45 -04:00
func ( i * ChartLoader ) loadRelease ( info chartInfo , helmWaitMode helm . WaitMode ) ( helm . Release , error ) {
2023-03-20 12:05:58 -04:00
chart , err := loadChartsDir ( helmFS , info . path )
2022-12-19 10:52:15 -05:00
if err != nil {
2023-03-20 12:05:58 -04:00
return helm . Release { } , fmt . Errorf ( "loading %s chart: %w" , info . releaseName , err )
2022-12-19 10:52:15 -05:00
}
2023-03-20 12:05:58 -04:00
2023-06-30 07:43:23 -04:00
var values map [ string ] any
2023-03-20 12:05:58 -04:00
switch info . releaseName {
case ciliumInfo . releaseName :
2023-07-20 03:40:14 -04:00
var ok bool
values , ok = ciliumVals [ i . csp . String ( ) ]
if ! ok {
return helm . Release { } , fmt . Errorf ( "cilium values for csp %q not found" , i . csp . String ( ) )
}
2023-03-20 12:05:58 -04:00
case certManagerInfo . releaseName :
values = i . loadCertManagerValues ( )
case constellationOperatorsInfo . releaseName :
updateVersions ( chart , compatibility . EnsurePrefixV ( constants . VersionInfo ( ) ) )
2023-06-26 04:13:28 -04:00
values = i . loadOperatorsValues ( )
2023-03-20 12:05:58 -04:00
case constellationServicesInfo . releaseName :
updateVersions ( chart , compatibility . EnsurePrefixV ( constants . VersionInfo ( ) ) )
2023-06-26 04:13:28 -04:00
values = i . loadConstellationServicesValues ( )
2023-07-24 04:30:53 -04:00
case awsLBControllerInfo . releaseName :
values = i . loadAWSLBControllerValues ( )
2023-06-26 04:13:28 -04:00
case csiInfo . releaseName :
updateVersions ( chart , compatibility . EnsurePrefixV ( constants . VersionInfo ( ) ) )
2023-06-30 07:43:23 -04:00
values = i . loadCSIValues ( )
2022-10-21 06:01:28 -04:00
}
chartRaw , err := i . marshalChart ( chart )
if err != nil {
2023-03-20 12:05:58 -04:00
return helm . Release { } , fmt . Errorf ( "packaging %s chart: %w" , info . releaseName , err )
2022-08-12 04:20:19 -04:00
}
2022-10-21 06:01:28 -04:00
2023-07-07 11:09:45 -04:00
return helm . Release { Chart : chartRaw , Values : values , ReleaseName : info . releaseName , WaitMode : helmWaitMode } , nil
2022-11-21 04:35:40 -05:00
}
2023-07-24 04:30:53 -04:00
func ( i * ChartLoader ) loadAWSLBControllerValues ( ) map [ string ] any {
return map [ string ] any {
"clusterName" : i . clusterName ,
"tolerations" : controlPlaneTolerations ,
"nodeSelector" : controlPlaneNodeSelector ,
}
}
2023-02-14 10:41:19 -05:00
// extendCiliumValues extends the given values map by some values depending on user input.
// This extra step of separating the application of user input is necessary since service upgrades should
// reuse user input from the init step. However, we can't rely on reuse-values, because
// during upgrades we all values need to be set locally as they might have changed.
// Also, the charts are not rendered correctly without all of these values.
func extendCiliumValues ( in map [ string ] any , conformanceMode bool ) {
2022-09-20 04:07:55 -04:00
if conformanceMode {
2023-02-14 10:41:19 -05:00
in [ "kubeProxyReplacementHealthzBindAddr" ] = ""
in [ "kubeProxyReplacement" ] = "partial"
in [ "sessionAffinity" ] = true
in [ "cni" ] = map [ string ] any {
2022-09-20 04:07:55 -04:00
"chainingMode" : "portmap" ,
}
}
2022-11-21 04:35:40 -05:00
}
// loadCertManagerHelper is used to separate the marshalling step from the loading step.
// This reduces the time unit tests take to execute.
2022-12-19 10:52:15 -05:00
func ( i * ChartLoader ) loadCertManagerValues ( ) map [ string ] any {
return map [ string ] any {
2022-11-21 04:35:40 -05:00
"installCRDs" : true ,
"prometheus" : map [ string ] any {
"enabled" : false ,
} ,
2023-07-20 03:33:45 -04:00
"tolerations" : controlPlaneTolerations ,
2022-11-21 04:35:40 -05:00
"webhook" : map [ string ] any {
2023-07-20 03:33:45 -04:00
"tolerations" : controlPlaneTolerations ,
2022-11-21 04:35:40 -05:00
} ,
"cainjector" : map [ string ] any {
2023-07-20 03:33:45 -04:00
"tolerations" : controlPlaneTolerations ,
2022-11-21 04:35:40 -05:00
} ,
"startupapicheck" : map [ string ] any {
2022-11-23 10:40:37 -05:00
"timeout" : "5m" ,
"extraArgs" : [ ] string {
"--verbose" ,
} ,
2023-07-20 03:33:45 -04:00
"tolerations" : controlPlaneTolerations ,
2022-11-21 04:35:40 -05:00
} ,
}
}
// loadOperatorsHelper is used to separate the marshalling step from the loading step.
// This reduces the time unit tests take to execute.
2023-06-26 04:13:28 -04:00
func ( i * ChartLoader ) loadOperatorsValues ( ) map [ string ] any {
return map [ string ] any {
2022-11-21 04:35:40 -05:00
"constellation-operator" : map [ string ] any {
"controllerManager" : map [ string ] any {
"manager" : map [ string ] any {
2022-11-28 03:15:39 -05:00
"image" : i . constellationOperatorImage ,
2022-11-21 04:35:40 -05:00
} ,
} ,
2023-06-26 04:13:28 -04:00
"csp" : i . csp . String ( ) ,
2022-11-21 04:35:40 -05:00
} ,
"node-maintenance-operator" : map [ string ] any {
"controllerManager" : map [ string ] any {
"manager" : map [ string ] any {
2022-11-28 03:15:39 -05:00
"image" : i . nodeMaintenanceOperatorImage ,
2022-11-21 04:35:40 -05:00
} ,
} ,
} ,
2023-06-30 07:43:23 -04:00
"tags" : i . cspTags ( ) ,
2022-11-21 04:35:40 -05:00
}
2022-10-18 07:15:54 -04:00
}
2022-11-21 04:35:40 -05:00
// loadConstellationServicesHelper is used to separate the marshalling step from the loading step.
// This reduces the time unit tests take to execute.
2023-06-26 04:13:28 -04:00
func ( i * ChartLoader ) loadConstellationServicesValues ( ) map [ string ] any {
return map [ string ] any {
2022-10-25 09:51:23 -04:00
"global" : map [ string ] any {
2023-01-20 12:51:06 -05:00
"keyServicePort" : constants . KeyServicePort ,
"keyServiceNamespace" : "" , // empty namespace means we use the release namespace
2023-01-11 04:08:57 -05:00
"serviceBasePath" : constants . ServiceBasePath ,
"joinConfigCMName" : constants . JoinConfigMap ,
"internalCMName" : constants . InternalConfigMap ,
2022-10-24 06:23:18 -04:00
} ,
2023-01-20 12:51:06 -05:00
"key-service" : map [ string ] any {
2023-05-03 05:11:53 -04:00
"image" : i . keyServiceImage ,
"saltKeyName" : constants . ConstellationSaltKey ,
"masterSecretKeyName" : constants . ConstellationMasterSecretKey ,
"masterSecretName" : constants . ConstellationMasterSecretStoreName ,
2022-10-24 06:23:18 -04:00
} ,
2022-10-25 09:51:23 -04:00
"join-service" : map [ string ] any {
2023-02-14 12:00:36 -05:00
"csp" : i . csp . String ( ) ,
2022-11-24 04:57:58 -05:00
"image" : i . joinServiceImage ,
2022-10-21 06:01:28 -04:00
} ,
2022-11-02 12:47:10 -04:00
"ccm" : map [ string ] any {
2023-06-26 04:13:28 -04:00
"csp" : i . csp . String ( ) ,
"image" : i . ccmImage ,
} ,
"cnm" : map [ string ] any {
2023-07-24 04:30:53 -04:00
"image" : i . azureCNMImage ,
2022-10-26 04:37:10 -04:00
} ,
2022-11-03 11:42:19 -04:00
"autoscaler" : map [ string ] any {
2023-02-14 12:00:36 -05:00
"csp" : i . csp . String ( ) ,
2022-11-03 11:42:19 -04:00
"image" : i . autoscalerImage ,
} ,
2022-11-21 11:06:41 -05:00
"verification-service" : map [ string ] any {
"image" : i . verificationServiceImage ,
} ,
2022-11-23 02:25:50 -05:00
"gcp-guest-agent" : map [ string ] any {
"image" : i . gcpGuestAgentImage ,
} ,
2022-11-23 02:26:09 -05:00
"konnectivity" : map [ string ] any {
"image" : i . konnectivityImage ,
} ,
2023-06-30 07:43:23 -04:00
"tags" : i . cspTags ( ) ,
}
}
func ( i * ChartLoader ) loadCSIValues ( ) map [ string ] any {
return map [ string ] any {
"tags" : i . cspTags ( ) ,
}
}
func ( i * ChartLoader ) cspTags ( ) map [ string ] any {
return map [ string ] any {
i . csp . String ( ) : true ,
2022-10-21 06:01:28 -04:00
}
}
2023-02-14 10:41:19 -05:00
// extendConstellationServicesValues extends the given values map by some values depending on user input.
2023-02-03 05:05:42 -05:00
// Values set inside this function are only applied during init, not during upgrade.
2023-03-21 07:46:49 -04:00
func extendConstellationServicesValues (
2023-05-03 05:11:53 -04:00
in map [ string ] any , cfg * config . Config , masterSecret , salt [ ] byte ,
2023-03-21 07:46:49 -04:00
) error {
2023-02-14 10:41:19 -05:00
keyServiceValues , ok := in [ "key-service" ] . ( map [ string ] any )
if ! ok {
return errors . New ( "missing 'key-service' key" )
}
keyServiceValues [ "masterSecret" ] = base64 . StdEncoding . EncodeToString ( masterSecret )
keyServiceValues [ "salt" ] = base64 . StdEncoding . EncodeToString ( salt )
2023-03-14 06:46:27 -04:00
joinServiceVals , ok := in [ "join-service" ] . ( map [ string ] any )
if ! ok {
return errors . New ( "invalid join-service values" )
}
2023-05-03 05:11:53 -04:00
joinServiceVals [ "attestationVariant" ] = cfg . GetAttestationConfig ( ) . GetVariant ( ) . String ( )
2023-03-14 06:46:27 -04:00
2023-05-03 05:11:53 -04:00
// attestation config is updated separately during upgrade,
2023-03-29 05:16:56 -04:00
// so we only set them in Helm during init.
2023-05-03 05:11:53 -04:00
attestationConfigJSON , err := json . Marshal ( cfg . GetAttestationConfig ( ) )
2023-03-29 05:16:56 -04:00
if err != nil {
return fmt . Errorf ( "marshalling measurements: %w" , err )
}
2023-05-03 05:11:53 -04:00
joinServiceVals [ "attestationConfig" ] = string ( attestationConfigJSON )
2023-03-29 05:16:56 -04:00
2023-03-14 06:46:27 -04:00
verifyServiceVals , ok := in [ "verification-service" ] . ( map [ string ] any )
if ! ok {
return errors . New ( "invalid verification-service values" )
}
2023-05-03 05:11:53 -04:00
verifyServiceVals [ "attestationVariant" ] = cfg . GetAttestationConfig ( ) . GetVariant ( ) . String ( )
2023-03-14 06:46:27 -04:00
2023-04-06 11:00:56 -04:00
csp := cfg . GetProvider ( )
2023-02-14 10:41:19 -05:00
switch csp {
2023-05-02 03:35:52 -04:00
case cloudprovider . OpenStack :
in [ "openstack" ] = map [ string ] any {
"deployYawolLoadBalancer" : cfg . DeployYawolLoadBalancer ( ) ,
}
if cfg . DeployYawolLoadBalancer ( ) {
in [ "yawol-controller" ] = map [ string ] any {
"yawolOSSecretName" : "yawolkey" ,
// has to be larger than ~30s to account for slow OpenStack API calls.
"openstackTimeout" : "1m" ,
"yawolFloatingID" : cfg . Provider . OpenStack . FloatingIPPoolID ,
"yawolFlavorID" : cfg . Provider . OpenStack . YawolFlavorID ,
"yawolImageID" : cfg . Provider . OpenStack . YawolImageID ,
}
}
2023-02-14 10:41:19 -05:00
}
return nil
}
2023-02-21 05:55:49 -05:00
// updateVersions changes all versions of direct dependencies that are set to "0.0.0" to newVersion.
func updateVersions ( chart * chart . Chart , newVersion string ) {
chart . Metadata . Version = newVersion
selectedDeps := chart . Metadata . Dependencies
for i := range selectedDeps {
if selectedDeps [ i ] . Version == "0.0.0" {
selectedDeps [ i ] . Version = newVersion
}
}
deps := chart . Dependencies ( )
for i := range deps {
if deps [ i ] . Metadata . Version == "0.0.0" {
deps [ i ] . Metadata . Version = newVersion
}
}
}
2022-10-21 06:01:28 -04:00
// marshalChart takes a Chart object, packages it to a temporary file and returns the content of that file.
// We currently need to take this approach of marshaling as dependencies are not marshaled correctly with json.Marshal.
// This stems from the fact that chart.Chart does not export the dependencies property.
func ( i * ChartLoader ) marshalChart ( chart * chart . Chart ) ( [ ] byte , error ) {
2022-10-31 14:25:02 -04:00
// A separate tmpdir path is necessary since during unit testing multiple go routines are accessing the same path, possibly deleting files for other routines.
tmpDirPath , err := os . MkdirTemp ( "" , "*" )
defer os . Remove ( tmpDirPath )
if err != nil {
return nil , fmt . Errorf ( "creating tmp dir: %w" , err )
}
path , err := chartutil . Save ( chart , tmpDirPath )
2022-10-21 06:01:28 -04:00
defer os . Remove ( path )
if err != nil {
2022-10-31 14:25:02 -04:00
return nil , fmt . Errorf ( "chartutil save: %w" , err )
2022-10-21 06:01:28 -04:00
}
chartRaw , err := os . ReadFile ( path )
if err != nil {
return nil , fmt . Errorf ( "reading packaged chart: %w" , err )
}
return chartRaw , nil
2022-08-12 04:20:19 -04:00
}
// taken from loader.LoadDir from the helm go module
// loadChartsDir loads from a directory.
//
// This loads charts only from directories.
2023-07-24 04:30:53 -04:00
// IMPORTANT: .helmignore rules specifying files in subdirectories are not applied (e.g. crds/kustomization.yaml).
2022-08-12 04:20:19 -04:00
func loadChartsDir ( efs embed . FS , dir string ) ( * chart . Chart , error ) {
utf8bom := [ ] byte { 0xEF , 0xBB , 0xBF }
// Just used for errors.
c := & chart . Chart { }
rules := ignore . Empty ( )
ifile , err := efs . ReadFile ( filepath . Join ( dir , ignore . HelmIgnore ) )
if err == nil {
r , err := ignore . Parse ( bytes . NewReader ( ifile ) )
if err != nil {
return c , err
}
rules = r
}
rules . AddDefaults ( )
files := [ ] * loader . BufferedFile { }
walk := func ( path string , d fs . DirEntry , err error ) error {
n := strings . TrimPrefix ( path , dir )
if n == "" {
// No need to process top level. Avoid bug with helmignore .* matching
// empty names. See issue https://github.com/kubernetes/helm/issues/1776.
return nil
}
// Normalize to / since it will also work on Windows
n = filepath . ToSlash ( n )
// Check input err
if err != nil {
return err
}
fi , err := d . Info ( )
if err != nil {
return err
}
if d . IsDir ( ) {
// Directory-based ignore rules should involve skipping the entire
// contents of that directory.
if rules . Ignore ( n , fi ) {
return filepath . SkipDir
}
return nil
}
// If a .helmignore file matches, skip this file.
if rules . Ignore ( n , fi ) {
return nil
}
// Irregular files include devices, sockets, and other uses of files that
// are not regular files. In Go they have a file mode type bit set.
// See https://golang.org/pkg/os/#FileMode for examples.
if ! fi . Mode ( ) . IsRegular ( ) {
return fmt . Errorf ( "cannot load irregular file %s as it has file mode type bits set" , path )
}
data , err := efs . ReadFile ( path )
if err != nil {
return errors . Wrapf ( err , "error reading %s" , n )
}
data = bytes . TrimPrefix ( data , utf8bom )
n = strings . TrimPrefix ( n , "/" )
files = append ( files , & loader . BufferedFile { Name : n , Data : data } )
return nil
}
if err := fs . WalkDir ( efs , dir , walk ) ; err != nil {
return c , err
}
return loader . LoadFiles ( files )
}