diff --git a/cmd/openshift-install/main.go b/cmd/openshift-install/main.go index deb87798867..eb30a265032 100644 --- a/cmd/openshift-install/main.go +++ b/cmd/openshift-install/main.go @@ -57,7 +57,6 @@ func runRootCmd(cmd *cobra.Command, args []string) error { level, err := logrus.ParseLevel(rootOpts.logLevel) if err != nil { return errors.Wrap(err, "invalid log-level") - } logrus.SetLevel(level) return nil diff --git a/cmd/openshift-install/targets.go b/cmd/openshift-install/targets.go index 4ed0c9db380..f8c70e81a9d 100644 --- a/cmd/openshift-install/targets.go +++ b/cmd/openshift-install/targets.go @@ -69,6 +69,10 @@ func newTargetsCmd() []*cobra.Command { func runTargetCmd(targets ...asset.WritableAsset) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { assetStore := &asset.StoreImpl{} + err := assetStore.Load(rootOpts.dir) + if err != nil { + logrus.Errorf("Could not load assets from state file: %v", err) + } for _, a := range targets { err := assetStore.Fetch(a) if err != nil { @@ -91,6 +95,11 @@ func runTargetCmd(targets ...asset.WritableAsset) func(cmd *cobra.Command, args return err } } + err = assetStore.Save(rootOpts.dir) + if err != nil { + errors.Wrapf(err, "failed to write to state file") + return err + } return nil } } diff --git a/pkg/asset/asset_test.go b/pkg/asset/asset_test.go index 4acb0c8e758..67fffd8acdf 100644 --- a/pkg/asset/asset_test.go +++ b/pkg/asset/asset_test.go @@ -26,11 +26,11 @@ func (a *persistAsset) Generate(Parents) error { type writablePersistAsset struct { persistAsset - files []*File + FileList []*File } func (a *writablePersistAsset) Files() []*File { - return a.files + return a.FileList } func TestPersistToFile(t *testing.T) { @@ -64,12 +64,12 @@ func TestPersistToFile(t *testing.T) { defer os.RemoveAll(dir) asset := &writablePersistAsset{ - files: make([]*File, len(tc.filenames)), + FileList: make([]*File, len(tc.filenames)), } expectedFiles := map[string][]byte{} for i, filename := range tc.filenames { data := []byte(fmt.Sprintf("data%d", i)) - asset.files[i] = &File{ + asset.FileList[i] = &File{ Filename: filename, Data: data, } diff --git a/pkg/asset/cluster/cluster.go b/pkg/asset/cluster/cluster.go index 7f8f4ab65f9..5d4f0a545b7 100644 --- a/pkg/asset/cluster/cluster.go +++ b/pkg/asset/cluster/cluster.go @@ -28,7 +28,7 @@ const ( // Cluster uses the terraform executable to launch a cluster // with the given terraform tfvar and generated templates. type Cluster struct { - files []*asset.File + FileList []*asset.File } var _ asset.WritableAsset = (*Cluster)(nil) @@ -67,7 +67,7 @@ func (c *Cluster) Generate(parents asset.Parents) (err error) { return errors.Wrap(err, "failed to write terraform.tfvars file") } - platform := terraformVariables.platform + platform := terraformVariables.Platform if err := data.Unpack(tmpDir, platform); err != nil { return err } @@ -78,7 +78,7 @@ func (c *Cluster) Generate(parents asset.Parents) (err error) { defer func() { if data, err2 := json.Marshal(metadata); err2 == nil { - c.files = append(c.files, &asset.File{ + c.FileList = append(c.FileList, &asset.File{ Filename: MetadataFilename, Data: data, }) @@ -90,7 +90,7 @@ func (c *Cluster) Generate(parents asset.Parents) (err error) { logrus.Error(err2) } } - // serialize metadata and stuff it into c.files + // serialize metadata and stuff it into c.FileList }() switch { @@ -135,7 +135,7 @@ func (c *Cluster) Generate(parents asset.Parents) (err error) { data, err2 := ioutil.ReadFile(stateFile) if err2 == nil { - c.files = append(c.files, &asset.File{ + c.FileList = append(c.FileList, &asset.File{ Filename: stateFileName, Data: data, }) @@ -151,7 +151,7 @@ func (c *Cluster) Generate(parents asset.Parents) (err error) { return err } -// Files returns the files generated by the asset. +// Files returns the FileList generated by the asset. func (c *Cluster) Files() []*asset.File { - return c.files + return c.FileList } diff --git a/pkg/asset/cluster/tfvars.go b/pkg/asset/cluster/tfvars.go index c93b4ff19f7..3d80b18cf8f 100644 --- a/pkg/asset/cluster/tfvars.go +++ b/pkg/asset/cluster/tfvars.go @@ -17,8 +17,8 @@ const ( // TerraformVariables depends on InstallConfig and // Ignition to generate the terrafor.tfvars. type TerraformVariables struct { - platform string - file *asset.File + Platform string + File *asset.File } var _ asset.WritableAsset = (*TerraformVariables)(nil) @@ -46,7 +46,7 @@ func (t *TerraformVariables) Generate(parents asset.Parents) error { worker := &machine.Worker{} parents.Get(installConfig, bootstrap, master, worker) - t.platform = installConfig.Config.Platform.Name() + t.Platform = installConfig.Config.Platform.Name() bootstrapIgn := string(bootstrap.Files()[0].Data) @@ -62,7 +62,7 @@ func (t *TerraformVariables) Generate(parents asset.Parents) error { if err != nil { return errors.Wrap(err, "failed to get Tfvars") } - t.file = &asset.File{ + t.File = &asset.File{ Filename: tfvarsFilename, Data: data, } @@ -72,8 +72,8 @@ func (t *TerraformVariables) Generate(parents asset.Parents) error { // Files returns the files generated by the asset. func (t *TerraformVariables) Files() []*asset.File { - if t.file != nil { - return []*asset.File{t.file} + if t.File != nil { + return []*asset.File{t.File} } return []*asset.File{} } diff --git a/pkg/asset/ignition/bootstrap/bootstrap.go b/pkg/asset/ignition/bootstrap/bootstrap.go index 0a4ea43a174..8be09a3388a 100644 --- a/pkg/asset/ignition/bootstrap/bootstrap.go +++ b/pkg/asset/ignition/bootstrap/bootstrap.go @@ -46,8 +46,8 @@ type bootstrapTemplateData struct { // Bootstrap is an asset that generates the ignition config for bootstrap nodes. type Bootstrap struct { - config *igntypes.Config - file *asset.File + Config *igntypes.Config + File *asset.File } var _ asset.WritableAsset = (*Bootstrap)(nil) @@ -89,7 +89,7 @@ func (a *Bootstrap) Generate(dependencies asset.Parents) error { return errors.Wrap(err, "failed to get bootstrap templates") } - a.config = &igntypes.Config{ + a.Config = &igntypes.Config{ Ignition: igntypes.Ignition{ Version: igntypes.MaxVersion.String(), }, @@ -100,23 +100,23 @@ func (a *Bootstrap) Generate(dependencies asset.Parents) error { a.addTectonicFiles(dependencies, templateData) a.addTLSCertFiles(dependencies) - a.config.Systemd.Units = append( - a.config.Systemd.Units, + a.Config.Systemd.Units = append( + a.Config.Systemd.Units, igntypes.Unit{Name: "bootkube.service", Contents: content.BootkubeSystemdContents}, igntypes.Unit{Name: "tectonic.service", Contents: content.TectonicSystemdContents, Enabled: util.BoolToPtr(true)}, igntypes.Unit{Name: "kubelet.service", Contents: applyTemplateData(content.KubeletSystemdTemplate, templateData), Enabled: util.BoolToPtr(true)}, ) - a.config.Passwd.Users = append( - a.config.Passwd.Users, + a.Config.Passwd.Users = append( + a.Config.Passwd.Users, igntypes.PasswdUser{Name: "core", SSHAuthorizedKeys: []igntypes.SSHAuthorizedKey{igntypes.SSHAuthorizedKey(installConfig.Config.Admin.SSHKey)}}, ) - data, err := json.Marshal(a.config) + data, err := json.Marshal(a.Config) if err != nil { return errors.Wrap(err, "failed to Marshal Ignition config") } - a.file = &asset.File{ + a.File = &asset.File{ Filename: "bootstrap.ign", Data: data, } @@ -131,8 +131,8 @@ func (a *Bootstrap) Name() string { // Files returns the files generated by the asset. func (a *Bootstrap) Files() []*asset.File { - if a.file != nil { - return []*asset.File{a.file} + if a.File != nil { + return []*asset.File{a.File} } return []*asset.File{} } @@ -174,13 +174,13 @@ func (a *Bootstrap) addBootstrapFiles(dependencies asset.Parents) { kubeCoreOperator := &manifests.KubeCoreOperator{} dependencies.Get(kubeletKubeconfig, kubeCoreOperator) - a.config.Storage.Files = append( - a.config.Storage.Files, + a.Config.Storage.Files = append( + a.Config.Storage.Files, ignition.FileFromBytes("/etc/kubernetes/kubeconfig", 0600, kubeletKubeconfig.Files()[0].Data), ignition.FileFromBytes("/var/lib/kubelet/kubeconfig", 0600, kubeletKubeconfig.Files()[0].Data), ) - a.config.Storage.Files = append( - a.config.Storage.Files, + a.Config.Storage.Files = append( + a.Config.Storage.Files, ignition.FilesFromAsset(rootDir, 0644, kubeCoreOperator)..., ) } @@ -190,16 +190,16 @@ func (a *Bootstrap) addBootkubeFiles(dependencies asset.Parents, templateData *b manifests := &manifests.Manifests{} dependencies.Get(adminKubeconfig, manifests) - a.config.Storage.Files = append( - a.config.Storage.Files, + a.Config.Storage.Files = append( + a.Config.Storage.Files, ignition.FileFromString("/opt/tectonic/bootkube.sh", 0555, applyTemplateData(content.BootkubeShFileTemplate, templateData)), ) - a.config.Storage.Files = append( - a.config.Storage.Files, + a.Config.Storage.Files = append( + a.Config.Storage.Files, ignition.FilesFromAsset(rootDir, 0600, adminKubeconfig)..., ) - a.config.Storage.Files = append( - a.config.Storage.Files, + a.Config.Storage.Files = append( + a.Config.Storage.Files, ignition.FilesFromAsset(rootDir, 0644, manifests)..., ) } @@ -208,12 +208,12 @@ func (a *Bootstrap) addTectonicFiles(dependencies asset.Parents, templateData *b tectonic := &manifests.Tectonic{} dependencies.Get(tectonic) - a.config.Storage.Files = append( - a.config.Storage.Files, + a.Config.Storage.Files = append( + a.Config.Storage.Files, ignition.FileFromString("/opt/tectonic/tectonic.sh", 0555, content.TectonicShFileContents), ) - a.config.Storage.Files = append( - a.config.Storage.Files, + a.Config.Storage.Files = append( + a.Config.Storage.Files, ignition.FilesFromAsset(rootDir, 0644, tectonic)..., ) } @@ -236,13 +236,13 @@ func (a *Bootstrap) addTLSCertFiles(dependencies asset.Parents) { &tls.ServiceAccountKeyPair{}, } { dependencies.Get(asset) - a.config.Storage.Files = append(a.config.Storage.Files, ignition.FilesFromAsset(rootDir, 0600, asset)...) + a.Config.Storage.Files = append(a.Config.Storage.Files, ignition.FilesFromAsset(rootDir, 0600, asset)...) } etcdClientCertKey := &tls.EtcdClientCertKey{} dependencies.Get(etcdClientCertKey) - a.config.Storage.Files = append( - a.config.Storage.Files, + a.Config.Storage.Files = append( + a.Config.Storage.Files, ignition.FileFromBytes("/etc/ssl/etcd/ca.crt", 0600, etcdClientCertKey.Cert()), ) } diff --git a/pkg/asset/ignition/machine/master.go b/pkg/asset/ignition/machine/master.go index a7383befabe..fd45c5320ff 100644 --- a/pkg/asset/ignition/machine/master.go +++ b/pkg/asset/ignition/machine/master.go @@ -14,8 +14,8 @@ import ( // Master is an asset that generates the ignition config for master nodes. type Master struct { - configs []*igntypes.Config - files []*asset.File + Configs []*igntypes.Config + FileList []*asset.File } var _ asset.WritableAsset = (*Master)(nil) @@ -34,18 +34,18 @@ func (a *Master) Generate(dependencies asset.Parents) error { rootCA := &tls.RootCA{} dependencies.Get(installConfig, rootCA) - a.configs = make([]*igntypes.Config, installConfig.Config.MasterCount()) - for i := range a.configs { - a.configs[i] = pointerIgnitionConfig(installConfig.Config, rootCA.Cert(), "master", fmt.Sprintf("etcd_index=%d", i)) + a.Configs = make([]*igntypes.Config, installConfig.Config.MasterCount()) + for i := range a.Configs { + a.Configs[i] = pointerIgnitionConfig(installConfig.Config, rootCA.Cert(), "master", fmt.Sprintf("etcd_index=%d", i)) } - a.files = make([]*asset.File, len(a.configs)) - for i, c := range a.configs { + a.FileList = make([]*asset.File, len(a.Configs)) + for i, c := range a.Configs { data, err := json.Marshal(c) if err != nil { return errors.Wrap(err, "failed to marshal ignition config") } - a.files[i] = &asset.File{ + a.FileList[i] = &asset.File{ Filename: fmt.Sprintf("master-%d.ign", i), Data: data, } @@ -61,5 +61,5 @@ func (a *Master) Name() string { // Files returns the files generated by the asset. func (a *Master) Files() []*asset.File { - return a.files + return a.FileList } diff --git a/pkg/asset/ignition/machine/worker.go b/pkg/asset/ignition/machine/worker.go index 8f4a5225dbc..ac08899e978 100644 --- a/pkg/asset/ignition/machine/worker.go +++ b/pkg/asset/ignition/machine/worker.go @@ -13,8 +13,8 @@ import ( // Worker is an asset that generates the ignition config for worker nodes. type Worker struct { - config *igntypes.Config - file *asset.File + Config *igntypes.Config + File *asset.File } var _ asset.WritableAsset = (*Worker)(nil) @@ -33,13 +33,13 @@ func (a *Worker) Generate(dependencies asset.Parents) error { rootCA := &tls.RootCA{} dependencies.Get(installConfig, rootCA) - a.config = pointerIgnitionConfig(installConfig.Config, rootCA.Cert(), "worker", "") + a.Config = pointerIgnitionConfig(installConfig.Config, rootCA.Cert(), "worker", "") - data, err := json.Marshal(a.config) + data, err := json.Marshal(a.Config) if err != nil { return errors.Wrap(err, "failed to get InstallConfig from parents") } - a.file = &asset.File{ + a.File = &asset.File{ Filename: "worker.ign", Data: data, } @@ -54,8 +54,8 @@ func (a *Worker) Name() string { // Files returns the files generated by the asset. func (a *Worker) Files() []*asset.File { - if a.file != nil { - return []*asset.File{a.file} + if a.File != nil { + return []*asset.File{a.File} } return []*asset.File{} } diff --git a/pkg/asset/installconfig/basedomain.go b/pkg/asset/installconfig/basedomain.go index aa6428e6a2b..9bfdab4a500 100644 --- a/pkg/asset/installconfig/basedomain.go +++ b/pkg/asset/installconfig/basedomain.go @@ -8,7 +8,7 @@ import ( ) type baseDomain struct { - baseDomain string + BaseDomain string } var _ asset.Asset = (*baseDomain)(nil) @@ -33,7 +33,7 @@ func (a *baseDomain) Generate(asset.Parents) error { }, "OPENSHIFT_INSTALL_BASE_DOMAIN", ) - a.baseDomain = bd + a.BaseDomain = bd return err } diff --git a/pkg/asset/installconfig/clusterid.go b/pkg/asset/installconfig/clusterid.go index 3d250ee5f5d..f075d1f53d0 100644 --- a/pkg/asset/installconfig/clusterid.go +++ b/pkg/asset/installconfig/clusterid.go @@ -7,7 +7,7 @@ import ( ) type clusterID struct { - clusterID string + ClusterID string } var _ asset.Asset = (*clusterID)(nil) @@ -19,7 +19,7 @@ func (a *clusterID) Dependencies() []asset.Asset { // Generate generates a new UUID func (a *clusterID) Generate(asset.Parents) error { - a.clusterID = uuid.New() + a.ClusterID = uuid.New() return nil } diff --git a/pkg/asset/installconfig/clustername.go b/pkg/asset/installconfig/clustername.go index 2d5f2c7b617..4ff7c6380ee 100644 --- a/pkg/asset/installconfig/clustername.go +++ b/pkg/asset/installconfig/clustername.go @@ -8,7 +8,7 @@ import ( ) type clusterName struct { - clusterName string + ClusterName string } var _ asset.Asset = (*clusterName)(nil) @@ -33,7 +33,7 @@ func (a *clusterName) Generate(asset.Parents) error { }, "OPENSHIFT_INSTALL_CLUSTER_NAME", ) - a.clusterName = n + a.ClusterName = n return err } diff --git a/pkg/asset/installconfig/emailaddress.go b/pkg/asset/installconfig/emailaddress.go index ece9f4209b0..ff714b94c07 100644 --- a/pkg/asset/installconfig/emailaddress.go +++ b/pkg/asset/installconfig/emailaddress.go @@ -8,7 +8,7 @@ import ( ) type emailAddress struct { - emailAddress string + EmailAddress string } var _ asset.Asset = (*emailAddress)(nil) @@ -33,7 +33,7 @@ func (a *emailAddress) Generate(asset.Parents) error { }, "OPENSHIFT_INSTALL_EMAIL_ADDRESS", ) - a.emailAddress = email + a.EmailAddress = email return err } diff --git a/pkg/asset/installconfig/installconfig.go b/pkg/asset/installconfig/installconfig.go index c81b7830d6c..286cd8258c2 100644 --- a/pkg/asset/installconfig/installconfig.go +++ b/pkg/asset/installconfig/installconfig.go @@ -24,8 +24,8 @@ var ( // InstallConfig generates the install-config.yml file. type InstallConfig struct { - Config *types.InstallConfig - file *asset.File + Config *types.InstallConfig `json:"config"` + File *asset.File `json:"file"` } var _ asset.WritableAsset = (*InstallConfig)(nil) @@ -68,15 +68,15 @@ func (a *InstallConfig) Generate(parents asset.Parents) error { a.Config = &types.InstallConfig{ ObjectMeta: metav1.ObjectMeta{ - Name: clusterName.clusterName, + Name: clusterName.ClusterName, }, - ClusterID: clusterID.clusterID, + ClusterID: clusterID.ClusterID, Admin: types.Admin{ - Email: emailAddress.emailAddress, - Password: password.password, - SSHKey: sshPublicKey.key, + Email: emailAddress.EmailAddress, + Password: password.Password, + SSHKey: sshPublicKey.Key, }, - BaseDomain: baseDomain.baseDomain, + BaseDomain: baseDomain.BaseDomain, Networking: types.Networking{ // TODO(yifan): Flannel is the temporal default network type for now, // Need to update it to the new types. @@ -89,19 +89,19 @@ func (a *InstallConfig) Generate(parents asset.Parents) error { IPNet: defaultPodCIDR, }, }, - PullSecret: pullSecret.pullSecret, + PullSecret: pullSecret.PullSecret, } numberOfMasters := int64(3) numberOfWorkers := int64(3) switch { - case platform.aws != nil: - a.Config.AWS = platform.aws - case platform.openstack != nil: - a.Config.OpenStack = platform.openstack - case platform.libvirt != nil: - a.Config.Libvirt = platform.libvirt - a.Config.Libvirt.Network.Name = clusterName.clusterName + case platform.AWS != nil: + a.Config.AWS = platform.AWS + case platform.Openstack != nil: + a.Config.OpenStack = platform.Openstack + case platform.Libvirt != nil: + a.Config.Libvirt = platform.Libvirt + a.Config.Libvirt.Network.Name = clusterName.ClusterName numberOfMasters = 1 numberOfWorkers = 1 default: @@ -123,7 +123,7 @@ func (a *InstallConfig) Generate(parents asset.Parents) error { if err != nil { return errors.Wrap(err, "failed to Marshal InstallConfig") } - a.file = &asset.File{ + a.File = &asset.File{ Filename: "install-config.yml", Data: data, } @@ -138,8 +138,8 @@ func (a *InstallConfig) Name() string { // Files returns the files generated by the asset. func (a *InstallConfig) Files() []*asset.File { - if a.file != nil { - return []*asset.File{a.file} + if a.File != nil { + return []*asset.File{a.File} } return []*asset.File{} } diff --git a/pkg/asset/installconfig/password.go b/pkg/asset/installconfig/password.go index 4045443296f..34c502c2c56 100644 --- a/pkg/asset/installconfig/password.go +++ b/pkg/asset/installconfig/password.go @@ -7,7 +7,7 @@ import ( ) type password struct { - password string + Password string } var _ asset.Asset = (*password)(nil) @@ -29,7 +29,7 @@ func (a *password) Generate(asset.Parents) error { }, "OPENSHIFT_INSTALL_PASSWORD", ) - a.password = p + a.Password = p return err } diff --git a/pkg/asset/installconfig/platform.go b/pkg/asset/installconfig/platform.go index f0c191b4119..cac8284b6d9 100644 --- a/pkg/asset/installconfig/platform.go +++ b/pkg/asset/installconfig/platform.go @@ -58,9 +58,9 @@ var ( // Platform is an asset that queries the user for the platform on which to install // the cluster. type platform struct { - aws *types.AWSPlatform - openstack *types.OpenStackPlatform - libvirt *types.LibvirtPlatform + AWS *types.AWSPlatform + Openstack *types.OpenStackPlatform + Libvirt *types.LibvirtPlatform } var _ asset.Asset = (*platform)(nil) @@ -83,19 +83,19 @@ func (a *platform) Generate(asset.Parents) error { if err != nil { return err } - a.aws = aws + a.AWS = aws case OpenStackPlatformType: openstack, err := a.openstackPlatform() if err != nil { return err } - a.openstack = openstack + a.Openstack = openstack case LibvirtPlatformType: libvirt, err := a.libvirtPlatform() if err != nil { return err } - a.libvirt = libvirt + a.Libvirt = libvirt default: return fmt.Errorf("unknown platform type %q", platform) } diff --git a/pkg/asset/installconfig/pullsecret.go b/pkg/asset/installconfig/pullsecret.go index de5d7edf99c..1e016028509 100644 --- a/pkg/asset/installconfig/pullsecret.go +++ b/pkg/asset/installconfig/pullsecret.go @@ -8,7 +8,7 @@ import ( ) type pullSecret struct { - pullSecret string + PullSecret string } var _ asset.Asset = (*pullSecret)(nil) @@ -34,7 +34,7 @@ func (a *pullSecret) Generate(asset.Parents) error { "OPENSHIFT_INSTALL_PULL_SECRET", "OPENSHIFT_INSTALL_PULL_SECRET_PATH", ) - a.pullSecret = s + a.PullSecret = s return err } diff --git a/pkg/asset/installconfig/ssh.go b/pkg/asset/installconfig/ssh.go index b1011ff2f59..edeada86e32 100644 --- a/pkg/asset/installconfig/ssh.go +++ b/pkg/asset/installconfig/ssh.go @@ -20,7 +20,7 @@ const ( ) type sshPublicKey struct { - key string + Key string } var _ asset.Asset = (*sshPublicKey)(nil) @@ -54,7 +54,7 @@ func (a *sshPublicKey) Generate(asset.Parents) error { return errors.Wrap(err, "failed to validate public key") } } - a.key = value + a.Key = value return nil } @@ -85,7 +85,7 @@ func (a *sshPublicKey) Generate(asset.Parents) error { if len(pubKeys) == 1 { for _, value := range pubKeys { - a.key = value + a.Key = value } return nil } @@ -113,7 +113,7 @@ func (a *sshPublicKey) Generate(asset.Parents) error { return errors.Wrap(err, "failed UserInput for SSH public key") } - a.key = pubKeys[path] + a.Key = pubKeys[path] return nil } diff --git a/pkg/asset/kubeconfig/kubeconfig.go b/pkg/asset/kubeconfig/kubeconfig.go index 92ecc933880..413fae8dda2 100644 --- a/pkg/asset/kubeconfig/kubeconfig.go +++ b/pkg/asset/kubeconfig/kubeconfig.go @@ -14,8 +14,8 @@ import ( ) type kubeconfig struct { - config *clientcmd.Config - file *asset.File + Config *clientcmd.Config + File *asset.File } // generate generates the kubeconfig. @@ -26,7 +26,7 @@ func (k *kubeconfig) generate( userName string, filename string, ) error { - k.config = &clientcmd.Config{ + k.Config = &clientcmd.Config{ Clusters: []clientcmd.NamedCluster{ { Name: installConfig.ObjectMeta.Name, @@ -57,12 +57,12 @@ func (k *kubeconfig) generate( CurrentContext: userName, } - data, err := yaml.Marshal(k.config) + data, err := yaml.Marshal(k.Config) if err != nil { return errors.Wrap(err, "failed to Marshal kubeconfig") } - k.file = &asset.File{ + k.File = &asset.File{ Filename: filepath.Join("auth", filename), Data: data, } @@ -72,8 +72,8 @@ func (k *kubeconfig) generate( // Files returns the files generated by the asset. func (k *kubeconfig) Files() []*asset.File { - if k.file != nil { - return []*asset.File{k.file} + if k.File != nil { + return []*asset.File{k.File} } return []*asset.File{} } diff --git a/pkg/asset/manifests/kube-addon-operator.go b/pkg/asset/manifests/kube-addon-operator.go index f4084d3b458..0b6bb942c06 100644 --- a/pkg/asset/manifests/kube-addon-operator.go +++ b/pkg/asset/manifests/kube-addon-operator.go @@ -13,8 +13,8 @@ import ( // kubeAddonOperator generates the network-operator-*.yml files type kubeAddonOperator struct { - config *kubeaddon.OperatorConfig - file *asset.File + Config *kubeaddon.OperatorConfig + File *asset.File } var _ asset.WritableAsset = (*kubeAddonOperator)(nil) @@ -37,7 +37,7 @@ func (kao *kubeAddonOperator) Generate(dependencies asset.Parents) error { installConfig := &installconfig.InstallConfig{} dependencies.Get(installConfig) - kao.config = &kubeaddon.OperatorConfig{ + kao.Config = &kubeaddon.OperatorConfig{ TypeMeta: metav1.TypeMeta{ APIVersion: kubeaddon.APIVersion, Kind: kubeaddon.Kind, @@ -49,12 +49,12 @@ func (kao *kubeAddonOperator) Generate(dependencies asset.Parents) error { }, } - data, err := yaml.Marshal(kao.config) + data, err := yaml.Marshal(kao.Config) if err != nil { return errors.Wrapf(err, "failed to create %s config from InstallConfig", kao.Name()) } - kao.file = &asset.File{ + kao.File = &asset.File{ Filename: "kube-addon-operator-config.yml", Data: data, } @@ -64,8 +64,8 @@ func (kao *kubeAddonOperator) Generate(dependencies asset.Parents) error { // Files returns the files generated by the asset. func (kao *kubeAddonOperator) Files() []*asset.File { - if kao.file != nil { - return []*asset.File{kao.file} + if kao.File != nil { + return []*asset.File{kao.File} } return []*asset.File{} } diff --git a/pkg/asset/manifests/kube-core-operator.go b/pkg/asset/manifests/kube-core-operator.go index 95213994173..3b384b2c8d4 100644 --- a/pkg/asset/manifests/kube-core-operator.go +++ b/pkg/asset/manifests/kube-core-operator.go @@ -24,8 +24,8 @@ const ( // KubeCoreOperator generates the kube-core-operator.yaml files type KubeCoreOperator struct { - config *kubecore.OperatorConfig - file *asset.File + Config *kubecore.OperatorConfig + File *asset.File } var _ asset.WritableAsset = (*KubeCoreOperator)(nil) @@ -53,7 +53,7 @@ func (kco *KubeCoreOperator) Generate(dependencies asset.Parents) error { return errors.Wrapf(err, "failed to create %s config from InstallConfig", kco.Name()) } - kco.config = &kubecore.OperatorConfig{ + kco.Config = &kubecore.OperatorConfig{ TypeMeta: metav1.TypeMeta{ APIVersion: kubecore.APIVersion, Kind: kubecore.Kind, @@ -85,11 +85,11 @@ func (kco *KubeCoreOperator) Generate(dependencies asset.Parents) error { }, } - data, err := yaml.Marshal(kco.config) + data, err := yaml.Marshal(kco.Config) if err != nil { return errors.Wrapf(err, "failed to create %s config from InstallConfig", kco.Name()) } - kco.file = &asset.File{ + kco.File = &asset.File{ Filename: "kco-config.yaml", Data: data, } @@ -99,8 +99,8 @@ func (kco *KubeCoreOperator) Generate(dependencies asset.Parents) error { // Files returns the files generated by the asset. func (kco *KubeCoreOperator) Files() []*asset.File { - if kco.file != nil { - return []*asset.File{kco.file} + if kco.File != nil { + return []*asset.File{kco.File} } return []*asset.File{} } diff --git a/pkg/asset/manifests/machine-api-operator.go b/pkg/asset/manifests/machine-api-operator.go index cd34963ed6d..5b1a06db695 100644 --- a/pkg/asset/manifests/machine-api-operator.go +++ b/pkg/asset/manifests/machine-api-operator.go @@ -21,8 +21,8 @@ const ( // machineAPIOperator generates the network-operator-*.yml files type machineAPIOperator struct { - config *maoOperatorConfig - file *asset.File + Config *maoOperatorConfig + File *asset.File } var _ asset.WritableAsset = (*machineAPIOperator)(nil) @@ -83,7 +83,7 @@ func (mao *machineAPIOperator) Generate(dependencies asset.Parents) error { aggregatorCA := &tls.AggregatorCA{} dependencies.Get(installConfig, aggregatorCA) - mao.config = &maoOperatorConfig{ + mao.Config = &maoOperatorConfig{ TypeMeta: metav1.TypeMeta{ APIVersion: "v1", Kind: "machineAPIOperatorConfig", @@ -102,7 +102,7 @@ func (mao *machineAPIOperator) Generate(dependencies asset.Parents) error { return errors.Wrapf(err, "failed to get AMI for %s config", mao.Name()) } - mao.config.AWS = &awsConfig{ + mao.Config.AWS = &awsConfig{ ClusterName: installConfig.Config.ObjectMeta.Name, ClusterID: installConfig.Config.ClusterID, Region: installConfig.Config.Platform.AWS.Region, @@ -111,7 +111,7 @@ func (mao *machineAPIOperator) Generate(dependencies asset.Parents) error { Replicas: int(*installConfig.Config.Machines[1].Replicas), } case installConfig.Config.Platform.Libvirt != nil: - mao.config.Libvirt = &libvirtConfig{ + mao.Config.Libvirt = &libvirtConfig{ ClusterName: installConfig.Config.ObjectMeta.Name, URI: installConfig.Config.Platform.Libvirt.URI, NetworkName: installConfig.Config.Platform.Libvirt.Network.Name, @@ -119,7 +119,7 @@ func (mao *machineAPIOperator) Generate(dependencies asset.Parents) error { Replicas: int(*installConfig.Config.Machines[1].Replicas), } case installConfig.Config.Platform.OpenStack != nil: - mao.config.OpenStack = &openstackConfig{ + mao.Config.OpenStack = &openstackConfig{ ClusterName: installConfig.Config.ObjectMeta.Name, ClusterID: installConfig.Config.ClusterID, Region: installConfig.Config.Platform.OpenStack.Region, @@ -129,11 +129,11 @@ func (mao *machineAPIOperator) Generate(dependencies asset.Parents) error { return errors.Errorf("unknown provider for machine-api-operator") } - data, err := yaml.Marshal(mao.config) + data, err := yaml.Marshal(mao.Config) if err != nil { return errors.Wrapf(err, "failed to marshal %s config", mao.Name()) } - mao.file = &asset.File{ + mao.File = &asset.File{ Filename: "machine-api-operator-config.yml", Data: data, } @@ -143,5 +143,5 @@ func (mao *machineAPIOperator) Generate(dependencies asset.Parents) error { // Files returns the files generated by the asset. func (mao *machineAPIOperator) Files() []*asset.File { - return []*asset.File{mao.file} + return []*asset.File{mao.File} } diff --git a/pkg/asset/manifests/network-operator.go b/pkg/asset/manifests/network-operator.go index acea3c1204d..82ad448404d 100644 --- a/pkg/asset/manifests/network-operator.go +++ b/pkg/asset/manifests/network-operator.go @@ -17,8 +17,8 @@ const ( // networkOperator generates the network-operator-*.yml files type networkOperator struct { - config *tectonicnetwork.OperatorConfig - files []*asset.File + config *tectonicnetwork.OperatorConfig + FileList []*asset.File } var _ asset.WritableAsset = (*networkOperator)(nil) @@ -57,7 +57,7 @@ func (no *networkOperator) Generate(dependencies asset.Parents) error { if err != nil { return errors.Wrapf(err, "failed to create %s manifests from InstallConfig", no.Name()) } - no.files = []*asset.File{ + no.FileList = []*asset.File{ { Filename: "network-operator-config.yml", Data: configData, @@ -73,5 +73,5 @@ func (no *networkOperator) Generate(dependencies asset.Parents) error { // Files returns the files generated by the asset. func (no *networkOperator) Files() []*asset.File { - return no.files + return no.FileList } diff --git a/pkg/asset/manifests/operators.go b/pkg/asset/manifests/operators.go index d8074d5bfab..c56a1ac4631 100644 --- a/pkg/asset/manifests/operators.go +++ b/pkg/asset/manifests/operators.go @@ -25,9 +25,9 @@ const ( // Manifests generates the dependent operator config.yaml files type Manifests struct { - kubeSysConfig *configurationObject - tectonicConfig *configurationObject - files []*asset.File + KubeSysConfig *configurationObject + TectonicConfig *configurationObject + FileList []*asset.File } var _ asset.WritableAsset = (*Manifests)(nil) @@ -78,27 +78,27 @@ func (m *Manifests) Generate(dependencies asset.Parents) error { dependencies.Get(kco, no, addon, mao, installConfig) // kco+no+mao go to kube-system config map - m.kubeSysConfig = configMap("kube-system", "cluster-config-v1", genericData{ + m.KubeSysConfig = configMap("kube-system", "cluster-config-v1", genericData{ "kco-config": string(kco.Files()[0].Data), "network-config": string(no.Files()[0].Data), "install-config": string(installConfig.Files()[0].Data), "mao-config": string(mao.Files()[0].Data), }) - kubeSysConfigData, err := yaml.Marshal(m.kubeSysConfig) + kubeSysConfigData, err := yaml.Marshal(m.KubeSysConfig) if err != nil { return errors.Wrap(err, "failed to create kube-system/cluster-config-v1 configmap") } // addon goes to openshift system - m.tectonicConfig = configMap("tectonic-system", "cluster-config-v1", genericData{ + m.TectonicConfig = configMap("tectonic-system", "cluster-config-v1", genericData{ "addon-config": string(addon.Files()[0].Data), }) - tectonicConfigData, err := yaml.Marshal(m.tectonicConfig) + tectonicConfigData, err := yaml.Marshal(m.TectonicConfig) if err != nil { return errors.Wrap(err, "failed to create tectonic-system/cluster-config-v1 configmap") } - m.files = []*asset.File{ + m.FileList = []*asset.File{ { Filename: filepath.Join(manifestDir, "cluster-config.yaml"), Data: kubeSysConfigData, @@ -108,14 +108,14 @@ func (m *Manifests) Generate(dependencies asset.Parents) error { Data: tectonicConfigData, }, } - m.files = append(m.files, m.generateBootKubeManifests(dependencies)...) + m.FileList = append(m.FileList, m.generateBootKubeManifests(dependencies)...) return nil } // Files returns the files generated by the asset. func (m *Manifests) Files() []*asset.File { - return m.files + return m.FileList } func (m *Manifests) generateBootKubeManifests(dependencies asset.Parents) []*asset.File { diff --git a/pkg/asset/manifests/tectonic.go b/pkg/asset/manifests/tectonic.go index de6ef0d4f25..d0b360f1574 100644 --- a/pkg/asset/manifests/tectonic.go +++ b/pkg/asset/manifests/tectonic.go @@ -13,7 +13,7 @@ import ( // Tectonic generates the dependent resource manifests for tectonic (as against bootkube) type Tectonic struct { - files []*asset.File + FileList []*asset.File } var _ asset.WritableAsset = (*Tectonic)(nil) @@ -73,9 +73,9 @@ func (t *Tectonic) Generate(dependencies asset.Parents) error { "99_tectonic-system-02-pull.json": applyTemplateData(content.PullTectonicSystem, templateData), } - t.files = make([]*asset.File, 0, len(assetData)) + t.FileList = make([]*asset.File, 0, len(assetData)) for name, data := range assetData { - t.files = append(t.files, &asset.File{ + t.FileList = append(t.FileList, &asset.File{ Filename: filepath.Join("tectonic", name), Data: data, }) @@ -86,5 +86,5 @@ func (t *Tectonic) Generate(dependencies asset.Parents) error { // Files returns the files generated by the asset. func (t *Tectonic) Files() []*asset.File { - return t.files + return t.FileList } diff --git a/pkg/asset/store.go b/pkg/asset/store.go index 7de7930fa04..c9b63be5ad6 100644 --- a/pkg/asset/store.go +++ b/pkg/asset/store.go @@ -1,12 +1,20 @@ package asset import ( + "encoding/json" + "io/ioutil" + "os" + "path/filepath" "reflect" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) +const ( + stateFileName = ".openshift_install_state.json" +) + // Store is a store for the states of assets. type Store interface { // Fetch retrieves the state of the given asset, generating it and its @@ -16,7 +24,8 @@ type Store interface { // StoreImpl is the implementation of Store. type StoreImpl struct { - assets map[reflect.Type]Asset + assets map[reflect.Type]Asset + stateFileAssets map[string]json.RawMessage } // Fetch retrieves the state of the given asset, generating it and its @@ -25,6 +34,58 @@ func (s *StoreImpl) Fetch(asset Asset) error { return s.fetch(asset, "") } +// Load retrieves the state from the state file present in the given directory +// and returns the assets map +func (s *StoreImpl) Load(dir string) error { + path := filepath.Join(dir, stateFileName) + assets := make(map[string]json.RawMessage) + data, err := ioutil.ReadFile(path) + if err != nil { + if os.IsNotExist(err) { + return nil + } + return err + } + err = json.Unmarshal(data, &assets) + if err != nil { + return errors.Wrapf(err, "failed to unmarshal state file %s", path) + } + s.stateFileAssets = assets + return nil +} + +// GetStateAsset renders the asset object arguments from the state file contents +// also returns a boolean indicating whether the object was found in the state file or not +func (s *StoreImpl) GetStateAsset(asset Asset) (bool, error) { + bytes, ok := s.stateFileAssets[reflect.TypeOf(asset).String()] + if !ok { + return false, nil + } + err := json.Unmarshal(bytes, asset) + return true, err +} + +// Save dumps the entire state map into a file +func (s *StoreImpl) Save(dir string) error { + assetMap := make(map[string]Asset) + for k, v := range s.assets { + assetMap[k.String()] = v + } + data, err := json.MarshalIndent(&assetMap, "", " ") + if err != nil { + return err + } + + path := filepath.Join(dir, stateFileName) + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + return err + } + if err := ioutil.WriteFile(path, data, 0644); err != nil { + return err + } + return nil +} + func (s *StoreImpl) fetch(asset Asset, indent string) error { logrus.Debugf("%sFetching %s...", indent, asset.Name()) storedAsset, ok := s.assets[reflect.TypeOf(asset)] @@ -47,10 +108,21 @@ func (s *StoreImpl) fetch(asset Asset, indent string) error { parents.Add(d) } - logrus.Debugf("%sGenerating %s...", indent, asset.Name()) - err := asset.Generate(parents) + // Before generating the asset, look if we have it all ready in the state file + // if yes, then use it instead + logrus.Debugf("%sLooking up asset from state file: %s", indent, reflect.TypeOf(asset).String()) + ok, err := s.GetStateAsset(asset) if err != nil { - return errors.Wrapf(err, "failed to generate asset %s", asset.Name()) + return errors.Wrapf(err, "failed to unmarshal asset '%s' from state file '%s'", asset.Name(), stateFileName) + } + if ok { + logrus.Debugf("%sAsset found in state file", indent) + } else { + logrus.Debugf("%sAsset not found in state file. Generating %s...", indent, asset.Name()) + err := asset.Generate(parents) + if err != nil { + return errors.Wrapf(err, "failed to generate asset %s", asset.Name()) + } } if s.assets == nil { s.assets = make(map[reflect.Type]Asset) diff --git a/pkg/asset/tls/certkey.go b/pkg/asset/tls/certkey.go index 2badf605e0a..48976bfb19f 100644 --- a/pkg/asset/tls/certkey.go +++ b/pkg/asset/tls/certkey.go @@ -32,19 +32,19 @@ type CertKeyInterface interface { // CertKey contains the private key and the cert that's // signed by the parent CA. type CertKey struct { - cert []byte - key []byte - files []*asset.File + CertRaw []byte + KeyRaw []byte + FileList []*asset.File } // Cert returns the certificate. func (c *CertKey) Cert() []byte { - return c.cert + return c.CertRaw } // Key returns the private key. func (c *CertKey) Key() []byte { - return c.key + return c.KeyRaw } // Generate generates a cert/key pair signed by the specified parent CA. @@ -73,11 +73,11 @@ func (c *CertKey) Generate( return errors.Wrap(err, "failed to generate cert/key pair") } - c.key = PrivateKeyToPem(key) - c.cert = CertToPem(crt) + c.KeyRaw = PrivateKeyToPem(key) + c.CertRaw = CertToPem(crt) if appendParent { - c.cert = bytes.Join([][]byte{c.cert, CertToPem(caCert)}, []byte("\n")) + c.CertRaw = bytes.Join([][]byte{c.CertRaw, CertToPem(caCert)}, []byte("\n")) } c.generateFiles(filenameBase) @@ -87,18 +87,18 @@ func (c *CertKey) Generate( // Files returns the files generated by the asset. func (c *CertKey) Files() []*asset.File { - return c.files + return c.FileList } func (c *CertKey) generateFiles(filenameBase string) { - c.files = []*asset.File{ + c.FileList = []*asset.File{ { Filename: assetFilePath(filenameBase + ".key"), - Data: c.key, + Data: c.KeyRaw, }, { Filename: assetFilePath(filenameBase + ".crt"), - Data: c.cert, + Data: c.CertRaw, }, } } diff --git a/pkg/asset/tls/keypair.go b/pkg/asset/tls/keypair.go index 79e243eee67..f2efb5d9fca 100644 --- a/pkg/asset/tls/keypair.go +++ b/pkg/asset/tls/keypair.go @@ -15,9 +15,9 @@ type KeyPairInterface interface { // KeyPair contains a private key and a public key. type KeyPair struct { - private []byte - public []byte - files []*asset.File + Pvt []byte + Pub []byte + FileList []*asset.File } // Generate generates the rsa private / public key pair. @@ -32,17 +32,17 @@ func (k *KeyPair) Generate(filenameBase string) error { return errors.Wrap(err, "failed to get public key data from private key") } - k.private = PrivateKeyToPem(key) - k.public = pubkeyData + k.Pvt = PrivateKeyToPem(key) + k.Pub = pubkeyData - k.files = []*asset.File{ + k.FileList = []*asset.File{ { Filename: assetFilePath(filenameBase + ".key"), - Data: k.private, + Data: k.Pvt, }, { Filename: assetFilePath(filenameBase + ".pub"), - Data: k.public, + Data: k.Pub, }, } @@ -51,15 +51,15 @@ func (k *KeyPair) Generate(filenameBase string) error { // Public returns the public key. func (k *KeyPair) Public() []byte { - return k.public + return k.Pub } // Private returns the private key. func (k *KeyPair) Private() []byte { - return k.private + return k.Pvt } // Files returns the files generated by the asset. func (k *KeyPair) Files() []*asset.File { - return k.files + return k.FileList } diff --git a/pkg/asset/tls/root.go b/pkg/asset/tls/root.go index 8dadabc67cc..3651f15391e 100644 --- a/pkg/asset/tls/root.go +++ b/pkg/asset/tls/root.go @@ -35,8 +35,8 @@ func (c *RootCA) Generate(parents asset.Parents) error { return errors.Wrap(err, "failed to generate RootCA") } - c.key = PrivateKeyToPem(key) - c.cert = CertToPem(crt) + c.KeyRaw = PrivateKeyToPem(key) + c.CertRaw = CertToPem(crt) c.generateFiles("root-ca")