Skip to content
Closed
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
54 changes: 54 additions & 0 deletions cmd/cluster-bootstrap/ibip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package main

import (
"errors"
"github.com/openshift/cluster-bootstrap/pkg/ibip"
"github.com/spf13/cobra"

)

var (
cmdIBip = &cobra.Command{
Use: "ibip",
Short: "Update the master ignition with control plane static pods files",
Long: "",
PreRunE: validateIBipOpts,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no ibip please :)

RunE: runCmdIBip,
SilenceUsage: true,
}

iBipOpts struct {
assetDir string
ignitionPath string
}
)

func init() {
cmdRoot.AddCommand(cmdIBip)
cmdIBip.Flags().StringVar(&iBipOpts.assetDir, "asset-dir", "", "Path to the cluster asset directory.")
cmdIBip.Flags().StringVar(&iBipOpts.ignitionPath, "ignition-path", "/assets/master.ign", "The location of master ignition")

}

func runCmdIBip(cmd *cobra.Command, args []string) error {

ib, err := ibip.NewIBipCommand(ibip.ConfigIBip{
AssetDir: iBipOpts.assetDir,
IgnitionPath: iBipOpts.ignitionPath,
})
if err != nil {
return err
}

return ib.UpdateSnoIgnitionData()
}

func validateIBipOpts(cmd *cobra.Command, args []string) error {
if iBipOpts.ignitionPath == "" {
return errors.New("missing required flag: --ignition-path")
}
if iBipOpts.assetDir == "" {
return errors.New("missing required flag: --asset-dir")
}
return nil
}
3 changes: 3 additions & 0 deletions cmd/cluster-bootstrap/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ var (
requiredPodClauses []string
waitForTearDownEvent string
earlyTearDown bool
clusterProfile string
}
)

Expand All @@ -44,6 +45,7 @@ func init() {
cmdStart.Flags().StringSliceVar(&startOpts.requiredPodClauses, "required-pods", defaultRequiredPods, "List of pods name prefixes with their namespace (written as <namespace>/<pod-prefix>) that are required to be running and ready before the start command does the pivot, or alternatively a list of or'ed pod prefixes with a description (written as <desc>:<namespace>/<pod-prefix>|<namespace>/<pod-prefix>|...).")
cmdStart.Flags().StringVar(&startOpts.waitForTearDownEvent, "tear-down-event", "", "if this optional event name of the form <ns>/<event-name> is given, the event is waited for before tearing down the bootstrap control plane")
cmdStart.Flags().BoolVar(&startOpts.earlyTearDown, "tear-down-early", true, "tear down immediate after the non-bootstrap control plane is up and bootstrap-success event is created.")
cmdStart.Flags().StringVar(&startOpts.clusterProfile, "cluster-profile", "", "The cluster profile.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this? What happens with the file? Add proper docs.

}

func runCmdStart(cmd *cobra.Command, args []string) error {
Expand All @@ -59,6 +61,7 @@ func runCmdStart(cmd *cobra.Command, args []string) error {
RequiredPodPrefixes: podPrefixes,
WaitForTearDownEvent: startOpts.waitForTearDownEvent,
EarlyTearDown: startOpts.earlyTearDown,
ClusterProfile: startOpts.clusterProfile,
})
if err != nil {
return err
Expand Down
11 changes: 11 additions & 0 deletions pkg/common/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package common

import "fmt"

// All start command printing to stdout should go through this fmt.Printf wrapper.
// The stdout of the start command should convey information useful to a human sitting
// at a terminal watching their cluster bootstrap itself. Otherwise the message
// should go to stderr.
func UserOutput(format string, a ...interface{}) {
fmt.Printf(format, a...)
}
215 changes: 215 additions & 0 deletions pkg/ibip/ibip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
package ibip

import (
"encoding/base64"
"encoding/json"
"github.com/openshift/cluster-bootstrap/pkg/common"
"io/ioutil"
"os"
"path/filepath"
"strings"

ignition "github.com/coreos/ignition/v2/config/v3_1"
ignitionTypes "github.com/coreos/ignition/v2/config/v3_1/types"
)

type ConfigIBip struct {
AssetDir string
IgnitionPath string
}

type iBipCommand struct {
ignitionPath string
assetDir string
}


func NewIBipCommand(config ConfigIBip) (*iBipCommand, error) {
return &iBipCommand{
assetDir: config.AssetDir,
ignitionPath: config.IgnitionPath,
}, nil
}

const (
kubeDir = "/etc/kubernetes"
assetPathBootstrapManifests = "bootstrap-manifests"
manifests = "manifests"
bootstrapConfigs = "bootstrap-configs"
bootstrapSecrets = "bootstrap-secrets"
etcdDataDir = "/var/lib/etcd"
)

type ignitionFile struct {
filePath string
fileContents string
mode int
}

type filesToGather struct {
pathForSearch string
pattern string
ignitionPath string
}

func newIgnitionFile(path string, filePathInIgnition string) (*ignitionFile, error) {
content, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
encodedContent := "data:text/plain;charset=utf-8;base64," + base64.StdEncoding.EncodeToString(content)
return &ignitionFile{filePath: filePathInIgnition,
mode: 420, fileContents: encodedContent}, nil
}

func (i *iBipCommand) createListOfIgnitionFiles(files []string, searchedFolder string, folderInIgnition string) ([]*ignitionFile, error) {
var ignitionFiles []*ignitionFile
for _, path := range files {
// Take relative path
filePath := filepath.Join(folderInIgnition, strings.ReplaceAll(path, searchedFolder, ""))
fileToAdd, err := newIgnitionFile(path, filePath)
if err != nil {
common.UserOutput("Failed to read %s", path)
return nil, err
}
ignitionFiles = append(ignitionFiles, fileToAdd)
}
return ignitionFiles, nil
}

func (i *iBipCommand) createFilesList(filesToGatherList []filesToGather) ([]*ignitionFile, error) {
var fullList []*ignitionFile
for _, ft := range filesToGatherList {
files, err := i.findFiles(ft.pathForSearch, ft.pattern)
if err != nil {
common.UserOutput("Failed to search for files in %s with pattern %s, err %e", ft.pathForSearch, ft.pattern, err)
return nil, err
}
ignitionFiles, err := i.createListOfIgnitionFiles(files, ft.pathForSearch, ft.ignitionPath)
if err != nil {
common.UserOutput("Failed to create ignitionsFile list for in %s with ign path %s, err %e", ft.pathForSearch, ft.ignitionPath, err)
return nil, err
}
fullList = append(fullList, ignitionFiles...)
}
return fullList, nil
}

func (i *iBipCommand) UpdateSnoIgnitionData() error {

common.UserOutput("Creating ignition file objects from required folders")
filesFromFolders := []filesToGather{
{pathForSearch: filepath.Join(i.assetDir, assetPathBootstrapManifests), pattern: "kube*", ignitionPath: filepath.Join(kubeDir, manifests)},
{pathForSearch: filepath.Join(kubeDir, bootstrapConfigs), pattern: "*", ignitionPath: filepath.Join(kubeDir, bootstrapConfigs)},
{pathForSearch: filepath.Join(i.assetDir, "tls"), pattern: "*", ignitionPath: filepath.Join(kubeDir, bootstrapSecrets)},
{pathForSearch: filepath.Join(i.assetDir, "etcd-bootstrap/bootstrap-manifests/secrets"), pattern: "*", ignitionPath: filepath.Join(kubeDir, "static-pod-resources/etcd-member")},
{pathForSearch: etcdDataDir, pattern: "*", ignitionPath: etcdDataDir},
}

ignitionFileObjects, err := i.createFilesList(filesFromFolders)
if err != nil {
return err
}

common.UserOutput("Creating ignition file objects from files that require rename")
singleFilesWithNameChange := map[string]string{
filepath.Join(i.assetDir, "auth/kubeconfig-loopback"): filepath.Join(kubeDir, bootstrapSecrets+"/kubeconfig"),
filepath.Join(i.assetDir, "tls/etcd-ca-bundle.crt"): filepath.Join(kubeDir, "static-pod-resources/etcd-member/ca.crt"),
filepath.Join(i.assetDir, "etcd-bootstrap/bootstrap-manifests/etcd-member-pod.yaml"): filepath.Join(kubeDir, manifests+"/etcd-pod.yaml"),
}

for path, ignPath := range singleFilesWithNameChange {
fileToAdd, err := newIgnitionFile(path, ignPath)
if err != nil {
common.UserOutput("Error occurred while trying to create ignitionFile from %s with ign path %s, err : %e", path, ignPath, err)
return err
}
ignitionFileObjects = append(ignitionFileObjects, fileToAdd)
}

common.UserOutput("Ignition Path %s", i.ignitionPath)
err = i.addFilesToIgnitionFile(i.ignitionPath, ignitionFileObjects)
if err != nil {
common.UserOutput("Error occurred while trying to read %s : %e", i.ignitionPath, err)
return err
}

return nil
}

func (i *iBipCommand) addFilesToIgnitionObject(ignitionData []byte, files []*ignitionFile) ([]byte, error) {

ignitionOutput, _, err := ignition.Parse(ignitionData)
if err != nil {
return nil, err
}

for _, file := range files {
common.UserOutput("Adding file %s", file.filePath)
rootUser := "root"
iFile := ignitionTypes.File{
Node: ignitionTypes.Node{
Path: file.filePath,
Overwrite: nil,
Group: ignitionTypes.NodeGroup{},
User: ignitionTypes.NodeUser{Name: &rootUser},
},
FileEmbedded1: ignitionTypes.FileEmbedded1{
Append: []ignitionTypes.Resource{},
Contents: ignitionTypes.Resource{
Source: &file.fileContents,
},
Mode: &file.mode,
},
}
ignitionOutput.Storage.Files = append(ignitionOutput.Storage.Files, iFile)
}
return json.Marshal(ignitionOutput)
}

func (i *iBipCommand) addFilesToIgnitionFile(ignitionPath string, files []*ignitionFile) error {
common.UserOutput("Adding files %d to ignition %s", len(files), ignitionPath)
ignitionData, err := ioutil.ReadFile(ignitionPath)
if err != nil {
common.UserOutput("Error occurred while trying to read %s : %e", ignitionPath, err)
return err
}
newIgnitionData, err := i.addFilesToIgnitionObject(ignitionData, files)
if err != nil {
common.UserOutput("Failed to write new ignition to %s : %e", ignitionPath, err)
return err
}

err = ioutil.WriteFile(ignitionPath, newIgnitionData, os.ModePerm)
if err != nil {
common.UserOutput("Failed to write new ignition to %s", ignitionPath)
return err
}

return nil
}

func (i *iBipCommand) findFiles(root string, pattern string) ([]string, error) {
var matches []string
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if path == root {
return nil
}
if info.IsDir() {
return nil
}
if matched, err := filepath.Match(pattern, filepath.Base(path)); err != nil {
return err
} else if matched {
matches = append(matches, path)
}
return nil
})
if err != nil {
return nil, err
}
return matches, nil
}
6 changes: 4 additions & 2 deletions pkg/start/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"os"
"path/filepath"
"strings"

"github.com/openshift/cluster-bootstrap/pkg/common"
)

type bootstrapControlPlane struct {
Expand All @@ -24,7 +26,7 @@ func newBootstrapControlPlane(assetDir, podManifestPath string) *bootstrapContro
// Start seeds static manifests to the kubelet to launch the bootstrap control plane.
// Users should always ensure that Cleanup() is called even in the case of errors.
func (b *bootstrapControlPlane) Start() error {
UserOutput("Starting temporary bootstrap control plane...\n")
common.UserOutput("Starting temporary bootstrap control plane...\n")
// Make secrets temporarily available to bootstrap cluster.
if err := os.RemoveAll(bootstrapSecretsDir); err != nil {
return err
Expand Down Expand Up @@ -52,7 +54,7 @@ func (b *bootstrapControlPlane) Teardown() error {
return nil
}

UserOutput("Tearing down temporary bootstrap control plane...\n")
common.UserOutput("Tearing down temporary bootstrap control plane...\n")
if err := os.RemoveAll(bootstrapSecretsDir); err != nil {
return err
}
Expand Down
Loading