Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a machineconfig for IPI pointer ignition customizations #4413

Merged
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
5 changes: 5 additions & 0 deletions pkg/asset/ignition/bootstrap/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/openshift/installer/pkg/asset/ignition"
"github.com/openshift/installer/pkg/asset/ignition/bootstrap/baremetal"
"github.com/openshift/installer/pkg/asset/ignition/bootstrap/vsphere"
mcign "github.com/openshift/installer/pkg/asset/ignition/machine"
"github.com/openshift/installer/pkg/asset/installconfig"
"github.com/openshift/installer/pkg/asset/kubeconfig"
"github.com/openshift/installer/pkg/asset/machines"
Expand Down Expand Up @@ -82,6 +83,8 @@ func (a *Bootstrap) Dependencies() []asset.Asset {
&kubeconfig.AdminInternalClient{},
&kubeconfig.Kubelet{},
&kubeconfig.LoopbackClient{},
&mcign.MasterIgnitionCustomizations{},
&mcign.WorkerIgnitionCustomizations{},
&machines.Master{},
&machines.Worker{},
&manifests.Manifests{},
Expand Down Expand Up @@ -461,6 +464,8 @@ func (a *Bootstrap) addParentFiles(dependencies asset.Parents) {
&manifests.Openshift{},
&machines.Master{},
&machines.Worker{},
&mcign.MasterIgnitionCustomizations{},
&mcign.WorkerIgnitionCustomizations{},
} {
dependencies.Get(asset)

Expand Down
84 changes: 84 additions & 0 deletions pkg/asset/ignition/machine/master_ignition_customizations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package machine

import (
"path/filepath"

"github.com/ghodss/yaml"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"

"github.com/openshift/installer/pkg/asset"
"github.com/openshift/installer/pkg/asset/installconfig"
"github.com/openshift/installer/pkg/asset/tls"
mcfgv1 "github.com/openshift/machine-config-operator/pkg/apis/machineconfiguration.openshift.io/v1"
)

var (
masterMachineConfigFileName = filepath.Join(directory, "99_openshift-installer-ignition_master.yaml")
)

// MasterIgnitionCustomizations is an asset that checks for any customizations a user might
// have made to the pointer ignition configs before creating the cluster. If customizations
// are made, then the updates are reconciled as a MachineConfig file
type MasterIgnitionCustomizations struct {
File *asset.File
}

var _ asset.WritableAsset = (*MasterIgnitionCustomizations)(nil)

// Dependencies returns the dependencies for MasterIgnitionCustomizations
func (a *MasterIgnitionCustomizations) Dependencies() []asset.Asset {
return []asset.Asset{
&installconfig.InstallConfig{},
&tls.RootCA{},
&Master{},
}
}

// Generate queries for input from the user.
func (a *MasterIgnitionCustomizations) Generate(dependencies asset.Parents) error {
installConfig := &installconfig.InstallConfig{}
rootCA := &tls.RootCA{}
master := &Master{}
dependencies.Get(installConfig, rootCA, master)

defaultPointerIgnition := pointerIgnitionConfig(installConfig.Config, rootCA.Cert(), "master")
savedPointerIgnition := master.Config

if savedPointerIgnition != defaultPointerIgnition {
logrus.Infof("Master pointer ignition was modified. Saving contents to a machineconfig")
mc := &mcfgv1.MachineConfig{}
mc, err := generatePointerMachineConfig(*savedPointerIgnition, "master")
if err != nil {
return errors.Wrap(err, "failed to generate master installer machineconfig")
}
configData, err := yaml.Marshal(mc)
if err != nil {
return errors.Wrap(err, "failed to marshal master installer machineconfig")
}
a.File = &asset.File{
Filename: masterMachineConfigFileName,
Data: configData,
}
}

return nil
}

// Name returns the human-friendly name of the asset.
func (a *MasterIgnitionCustomizations) Name() string {
return "Master Ignition Customization Check"
}

// Files returns the files generated by the asset.
func (a *MasterIgnitionCustomizations) Files() []*asset.File {
if a.File != nil {
return []*asset.File{a.File}
}
return []*asset.File{}
}

// Load does nothing, since we consume the ignition-configs
func (a *MasterIgnitionCustomizations) Load(f asset.FileFetcher) (found bool, err error) {
return false, nil
}
50 changes: 50 additions & 0 deletions pkg/asset/ignition/machine/master_ignition_customizations_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package machine

import (
"testing"

"github.com/stretchr/testify/assert"

"github.com/openshift/installer/pkg/asset"
"github.com/openshift/installer/pkg/asset/installconfig"
"github.com/openshift/installer/pkg/asset/tls"
"github.com/openshift/installer/pkg/ipnet"
"github.com/openshift/installer/pkg/types"
"github.com/openshift/installer/pkg/types/aws"
)

// TestMasterIgnitionCustomizationsGenerate tests generating the master ignition check asset.
func TestMasterIgnitionCustomizationsGenerate(t *testing.T) {
installConfig := &installconfig.InstallConfig{
Config: &types.InstallConfig{
Networking: &types.Networking{
ServiceNetwork: []ipnet.IPNet{*ipnet.MustParseCIDR("10.0.1.0/24")},
},
Platform: types.Platform{
AWS: &aws.Platform{
Region: "us-east",
},
},
},
}

rootCA := &tls.RootCA{}
err := rootCA.Generate(nil)
assert.NoError(t, err, "unexpected error generating root CA")

parents := asset.Parents{}
parents.Add(installConfig, rootCA)

master := &Master{}
err = master.Generate(parents)
assert.NoError(t, err, "unexpected error generating master asset")

parents.Add(master)
masterIgnCheck := &MasterIgnitionCustomizations{}
err = masterIgnCheck.Generate(parents)
assert.NoError(t, err, "unexpected error generating master ignition check asset")

actualFiles := masterIgnCheck.Files()
assert.Equal(t, 1, len(actualFiles), "unexpected number of files in master state")
assert.Equal(t, masterMachineConfigFileName, actualFiles[0].Filename, "unexpected name for master ignition config")
}
33 changes: 33 additions & 0 deletions pkg/asset/ignition/machine/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,19 @@ import (
ignutil "github.com/coreos/ignition/v2/config/util"
igntypes "github.com/coreos/ignition/v2/config/v3_1/types"
"github.com/vincent-petithory/dataurl"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/openshift/installer/pkg/asset/ignition"
"github.com/openshift/installer/pkg/types"
baremetaltypes "github.com/openshift/installer/pkg/types/baremetal"
openstacktypes "github.com/openshift/installer/pkg/types/openstack"
ovirttypes "github.com/openshift/installer/pkg/types/ovirt"
vspheretypes "github.com/openshift/installer/pkg/types/vsphere"
mcfgv1 "github.com/openshift/machine-config-operator/pkg/apis/machineconfiguration.openshift.io/v1"
)

const directory = "openshift"

// pointerIgnitionConfig generates a config which references the remote config
// served by the machine config server.
func pointerIgnitionConfig(installConfig *types.InstallConfig, rootCA []byte, role string) *igntypes.Config {
Expand Down Expand Up @@ -61,3 +66,31 @@ func pointerIgnitionConfig(installConfig *types.InstallConfig, rootCA []byte, ro
},
}
}

// generatePointerMachineConfig generates a machineconfig when a user customizes
// the pointer ignition file manually in an IPI deployment
func generatePointerMachineConfig(config igntypes.Config, role string) (*mcfgv1.MachineConfig, error) {
// Remove the merge section from the pointer config
config.Ignition.Config.Merge = nil

rawExt, err := ignition.ConvertToRawExtension(config)
if err != nil {
return nil, err
}

return &mcfgv1.MachineConfig{
TypeMeta: metav1.TypeMeta{
APIVersion: mcfgv1.SchemeGroupVersion.String(),
Kind: "MachineConfig",
},
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("99-installer-ignition-%s", role),
Labels: map[string]string{
"machineconfiguration.openshift.io/role": role,
},
},
Spec: mcfgv1.MachineConfigSpec{
Config: rawExt,
},
}, nil
}
85 changes: 85 additions & 0 deletions pkg/asset/ignition/machine/worker_ignition_customizations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package machine

import (
"path/filepath"

"github.com/ghodss/yaml"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"

"github.com/openshift/installer/pkg/asset"
"github.com/openshift/installer/pkg/asset/installconfig"
"github.com/openshift/installer/pkg/asset/tls"
mcfgv1 "github.com/openshift/machine-config-operator/pkg/apis/machineconfiguration.openshift.io/v1"
)

var (
workerMachineConfigFileName = filepath.Join(directory, "99_openshift-installer-ignition_worker.yaml")
)

// WorkerIgnitionCustomizations is an asset that checks for any customizations a user might
// have made to the pointer ignition configs before creating the cluster. If customizations
// are made, then the updates are reconciled as a MachineConfig file
type WorkerIgnitionCustomizations struct {
File *asset.File
}

var _ asset.WritableAsset = (*WorkerIgnitionCustomizations)(nil)

// Dependencies returns the dependencies for WorkerIgnitionCustomizations
func (a *WorkerIgnitionCustomizations) Dependencies() []asset.Asset {
return []asset.Asset{
&installconfig.InstallConfig{},
&tls.RootCA{},
&Worker{},
}
}

// Generate queries for input from the user.
func (a *WorkerIgnitionCustomizations) Generate(dependencies asset.Parents) error {
installConfig := &installconfig.InstallConfig{}
rootCA := &tls.RootCA{}
worker := &Worker{}
dependencies.Get(installConfig, rootCA, worker)

defaultPointerIgnition := pointerIgnitionConfig(installConfig.Config, rootCA.Cert(), "worker")
savedPointerIgnition := worker.Config

// Create a machineconfig if the ignition has been modified
if savedPointerIgnition != defaultPointerIgnition {
logrus.Infof("Worker pointer ignition was modified. Saving contents to a machineconfig")
mc := &mcfgv1.MachineConfig{}
mc, err := generatePointerMachineConfig(*savedPointerIgnition, "worker")
if err != nil {
return errors.Wrap(err, "failed to generate worker installer machineconfig")
}
configData, err := yaml.Marshal(mc)
if err != nil {
return errors.Wrap(err, "failed to marshal worker installer machineconfig")
}
a.File = &asset.File{
Filename: workerMachineConfigFileName,
Data: configData,
}
}

return nil
}

// Name returns the human-friendly name of the asset.
func (a *WorkerIgnitionCustomizations) Name() string {
return "Worker Ignition Customization Check"
}

// Files returns the files generated by the asset.
func (a *WorkerIgnitionCustomizations) Files() []*asset.File {
if a.File != nil {
return []*asset.File{a.File}
}
return []*asset.File{}
}

// Load does nothing, since we consume the ignition-configs
func (a *WorkerIgnitionCustomizations) Load(f asset.FileFetcher) (found bool, err error) {
return false, nil
}
50 changes: 50 additions & 0 deletions pkg/asset/ignition/machine/worker_ignition_customizations_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package machine

import (
"testing"

"github.com/stretchr/testify/assert"

"github.com/openshift/installer/pkg/asset"
"github.com/openshift/installer/pkg/asset/installconfig"
"github.com/openshift/installer/pkg/asset/tls"
"github.com/openshift/installer/pkg/ipnet"
"github.com/openshift/installer/pkg/types"
"github.com/openshift/installer/pkg/types/aws"
)

// TestWorkerIgnitionCustomizationsGenerate tests generating the worker ignition check asset.
func TestWorkerIgnitionCustomizationsGenerate(t *testing.T) {
installConfig := &installconfig.InstallConfig{
Config: &types.InstallConfig{
Networking: &types.Networking{
ServiceNetwork: []ipnet.IPNet{*ipnet.MustParseCIDR("10.0.1.0/24")},
},
Platform: types.Platform{
AWS: &aws.Platform{
Region: "us-east",
},
},
},
}

rootCA := &tls.RootCA{}
err := rootCA.Generate(nil)
assert.NoError(t, err, "unexpected error generating root CA")

parents := asset.Parents{}
parents.Add(installConfig, rootCA)

worker := &Worker{}
err = worker.Generate(parents)
assert.NoError(t, err, "unexpected error generating worker asset")

parents.Add(worker)
workerIgnCheck := &WorkerIgnitionCustomizations{}
err = workerIgnCheck.Generate(parents)
assert.NoError(t, err, "unexpected error generating worker ignition check asset")

actualFiles := workerIgnCheck.Files()
assert.Equal(t, 1, len(actualFiles), "unexpected number of files in worker state")
assert.Equal(t, workerMachineConfigFileName, actualFiles[0].Filename, "unexpected name for worker ignition config")
}
2 changes: 2 additions & 0 deletions pkg/asset/targets/targets.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ var (
// Cluster are the cluster targeted assets.
Cluster = []asset.WritableAsset{
&cluster.Metadata{},
&machine.MasterIgnitionCustomizations{},
&machine.WorkerIgnitionCustomizations{},
&cluster.TerraformVariables{},
&kubeconfig.AdminClient{},
&password.KubeadminPassword{},
Expand Down