Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions cmd/render/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ var (
destinationDir string
clusterInfrastructure string
imagesFile string
cloudConfigFile string
}
)

Expand All @@ -32,6 +33,7 @@ func init() {
renderCmd.PersistentFlags().StringVar(&renderOpts.destinationDir, "dest-dir", "", "The destination dir where CCCMO writes the generated static pods for CCM.")
renderCmd.PersistentFlags().StringVar(&renderOpts.clusterInfrastructure, "cluster-infrastructure-file", "", "Input path for the cluster infrastructure file.")
renderCmd.PersistentFlags().StringVar(&renderOpts.imagesFile, "images-file", "", "Input path for the images config map file.")
renderCmd.PersistentFlags().StringVar(&renderOpts.cloudConfigFile, "cloud-config-file", "", "Input path for the cloud config configMap manifest generated by cluster-config-operator.")
renderCmd.MarkFlagRequired("dest-dir")
renderCmd.MarkFlagRequired("cluster-infrastructure-file")
renderCmd.MarkFlagRequired("images-file")
Expand All @@ -44,19 +46,23 @@ func runRenderCmd(cmd *cobra.Command, args []string) error {
if err := validate(
renderOpts.destinationDir,
renderOpts.clusterInfrastructure,
renderOpts.imagesFile); err != nil {
renderOpts.imagesFile,
renderOpts.cloudConfigFile); err != nil {
return err
}

if err := render.New(renderOpts.clusterInfrastructure, renderOpts.imagesFile).Run(renderOpts.destinationDir); err != nil {
if err := render.New(
renderOpts.clusterInfrastructure,
renderOpts.imagesFile,
renderOpts.cloudConfigFile).Run(renderOpts.destinationDir); err != nil {
return err
}

return nil
}

// validate verifies all file and dirs exist
func validate(destinationDir, clusterInfrastructure, imagesFile string) error {
func validate(destinationDir, clusterInfrastructure, imagesFile, cloudConfigFile string) error {
errs := []error{}
if err := isFile(clusterInfrastructure); err != nil {
klog.Errorf("error reading --cluster-infrastructure-file=%q: %s", clusterInfrastructure, err)
Expand All @@ -66,6 +72,12 @@ func validate(destinationDir, clusterInfrastructure, imagesFile string) error {
klog.Errorf("error reading --images-file=%q: %s", imagesFile, err)
errs = append(errs, fmt.Errorf("error reading --images-file: %s", err))
}
if cloudConfigFile != "" {
if err := isFile(cloudConfigFile); err != nil {
klog.Errorf("error reading --cloud-config-file=%q: %s", imagesFile, err)
errs = append(errs, fmt.Errorf("error reading --cloud-config-file: %s", err))
}
}

if len(errs) > 0 {
return utilerrors.NewAggregate(errs)
Expand Down
82 changes: 73 additions & 9 deletions pkg/render/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ import (
)

const (
configDataKey = "cloud.conf"
bootstrapNamespace = "kube-system"
bootstrapPrefix = "bootstrap"
configPrefix = "config"
// bootstrapFileName is built from bootstrapPrefix, resource name and kind
bootstrapFileName = "%s/%s-%s.yaml"
)
Expand All @@ -32,20 +34,24 @@ type Render struct {
infrastructureFile string
// path to rendered cloud-controller-manager-images ConfigMap manifest for image references to use
imagesFile string
// path to populated cloud-config ConfigMap manifest from cluster-config-operator
// where cloud-config could be extracted for use in CCM static pod
cloudConfigFile string
}

// New returns controller for render
func New(infrastructureFile, imagesFile string) *Render {
func New(infrastructureFile, imagesFile, cloudConfigFile string) *Render {
return &Render{
infrastructureFile: infrastructureFile,
imagesFile: imagesFile,
cloudConfigFile: cloudConfigFile,
}
}

// Run runs boostrap for Machine Config Controller
// It writes all the assets to destDir
func (r *Render) Run(destinationDir string) error {
infra, imagesMap, err := r.readAssets()
infra, imagesMap, cloudConfig, err := r.readAssets()
if err != nil {
klog.Errorf("Cannot read assets from provided paths: %v", err)
return err
Expand All @@ -63,36 +69,51 @@ func (r *Render) Run(destinationDir string) error {
klog.Infof("Collected resource %s %q successfully", resource.GetObjectKind().GroupVersionKind(), client.ObjectKeyFromObject(resource))
}

return writeAssets(destinationDir, resources)
if err := writeAssets(destinationDir, resources); err != nil {
klog.Errorf("Could not write assets to bootstrap dir: %v", err)
return err
}

return writeCloudConfig(destinationDir, cloudConfig)
}

// readAssets collects infrastructure resource and images config map from provided paths
func (r *Render) readAssets() (*configv1.Infrastructure, *corev1.ConfigMap, error) {
func (r *Render) readAssets() (*configv1.Infrastructure, *corev1.ConfigMap, string, error) {
infraData, err := ioutil.ReadFile(r.infrastructureFile)
if err != nil {
klog.Errorf("Unable to read data from %q: %v", r.infrastructureFile, err)
return nil, nil, err
return nil, nil, "", err
}

infra := &configv1.Infrastructure{}
if err := yaml.UnmarshalStrict(infraData, infra); err != nil {
klog.Errorf("Cannot decode data into configv1.Infrastructure from %q: %v", r.infrastructureFile, err)
return nil, nil, err
return nil, nil, "", err
}

imagesData, err := ioutil.ReadFile(r.imagesFile)
if err != nil {
klog.Errorf("Unable to read data from %q: %v", r.imagesFile, err)
return nil, nil, err
return nil, nil, "", err
}

imagesConfigMap := &corev1.ConfigMap{}
if err := yaml.UnmarshalStrict(imagesData, imagesConfigMap); err != nil {
klog.Errorf("Cannot decode data into v1.ConfigMap from %q: %v", r.imagesFile, err)
return nil, nil, err
return nil, nil, "", err
}

cloudConfig := ""
// if the cloudConfig is set in infra read the cloudConfigFile
if infra.Spec.CloudConfig.Name != "" {
cloudConfig, err = loadBootstrapCloudProviderConfig(infra, r.cloudConfigFile)
if err != nil {
klog.Errorf("failed to load the cloud provider config: %v", err)
return nil, nil, "", err
}
}

return infra, imagesConfigMap, nil
return infra, imagesConfigMap, cloudConfig, nil
}

// writeAssets writes static pods to disk into <destinationDir>/<bootstrapPrefix>/<resourceName>-<resourceKind>.yaml
Expand All @@ -118,5 +139,48 @@ func writeAssets(destinationDir string, resources []client.Object) error {
return err
}
}

return nil
}

// writeCloudConfig creates config folder and writes resources such as cloud-config file
// for use in bootstrap
func writeCloudConfig(destinationDir string, cloudConfig string) error {
// Create config directory in advance to ensure it is present for any provider
configDir := filepath.Join(destinationDir, configPrefix)
if err := os.MkdirAll(configDir, fs.ModePerm); err != nil {
klog.Errorf("Unable to create destination dir %q: %v", configDir, err)
return err
}

if cloudConfig != "" {
cloudConfigFile := filepath.Join(configDir, configDataKey)

klog.Infof("Writing cloud config on disk in %q", cloudConfigFile)
err := os.WriteFile(cloudConfigFile, []byte(cloudConfig), 0666)
if err != nil {
klog.Errorf("Failed to write cloud config to disk in %q: %v", cloudConfigFile, err)
return err
}
}

return nil
}

// loadBootstrapCloudProviderConfig reads the cloud provider config from cloudConfigFile based on infra object.
func loadBootstrapCloudProviderConfig(infra *configv1.Infrastructure, cloudConfigFile string) (string, error) {
data, err := os.ReadFile(cloudConfigFile)
if err != nil {
return "", err
}
cloudConfigMap := &corev1.ConfigMap{}
if err := yaml.UnmarshalStrict(data, cloudConfigMap); err != nil {
return "", err
}
cloudConf, ok := cloudConfigMap.Data[configDataKey]
if !ok {
klog.Infof("falling back to reading cloud provider config from user specified key %s", infra.Spec.CloudConfig.Key)
cloudConf = cloudConfigMap.Data[infra.Spec.CloudConfig.Key]
}
return cloudConf, nil
}
Loading