Skip to content

Commit 9552fc8

Browse files
Merge pull request openshift#7997 from andfasano/agent-day2-clusterinfo-asset
AGENT-853: Add ClusterInfo asset
2 parents 62209ca + d56bab4 commit 9552fc8

File tree

7 files changed

+344
-3
lines changed

7 files changed

+344
-3
lines changed

cmd/node-joiner/main.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ func main() {
1919
Use: "add-nodes",
2020
Short: "Generates an ISO that could be used to boot the configured nodes to let them join an existing cluster",
2121
RunE: func(cmd *cobra.Command, args []string) error {
22-
return nodejoiner.NewAddNodesCommand(wd)
22+
kubeConfig, err := cmd.Flags().GetString("kubeconfig")
23+
if err != nil {
24+
return err
25+
}
26+
return nodejoiner.NewAddNodesCommand(wd, kubeConfig)
2327
},
2428
}
2529

@@ -34,6 +38,7 @@ func main() {
3438
rootCmd := &cobra.Command{
3539
Use: "node-joiner",
3640
}
41+
rootCmd.PersistentFlags().String("kubeconfig", "", "Path to the kubeconfig file.")
3742

3843
rootCmd.AddCommand(nodesAddCmd)
3944
rootCmd.AddCommand(nodesMonitorCmd)
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package joiner
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"os"
7+
"path/filepath"
8+
9+
"github.com/openshift/installer/pkg/asset"
10+
)
11+
12+
const (
13+
addNodesParamsFile = ".addnodesparams"
14+
)
15+
16+
// AddNodesConfig is used to store the current configuration
17+
// for the command.
18+
type AddNodesConfig struct {
19+
File *asset.File
20+
Params Params
21+
}
22+
23+
// Params is used to store the command line parameters.
24+
type Params struct {
25+
Kubeconfig string `json:"kubeconfig,omitempty"`
26+
}
27+
28+
// Save stores the current parameters on disk.
29+
func (p *Params) Save(assetsDir string) error {
30+
data, err := json.Marshal(p)
31+
if err != nil {
32+
return err
33+
}
34+
35+
fileName := filepath.Join(assetsDir, addNodesParamsFile)
36+
return os.WriteFile(fileName, data, 0o600)
37+
}
38+
39+
// Name returns the human-friendly name of the asset.
40+
func (*AddNodesConfig) Name() string {
41+
return "AddNodes Config"
42+
}
43+
44+
// Dependencies returns all of the dependencies directly needed to generate
45+
// the asset.
46+
func (*AddNodesConfig) Dependencies() []asset.Asset {
47+
return []asset.Asset{}
48+
}
49+
50+
// Generate it's empty for this asset, always loaded from disk.
51+
func (*AddNodesConfig) Generate(dependencies asset.Parents) error {
52+
return nil
53+
}
54+
55+
// Files returns the files generated by the asset.
56+
func (a *AddNodesConfig) Files() []*asset.File {
57+
if a.File != nil {
58+
return []*asset.File{a.File}
59+
}
60+
return []*asset.File{}
61+
}
62+
63+
// Load returns agent config asset from the disk.
64+
func (a *AddNodesConfig) Load(f asset.FileFetcher) (bool, error) {
65+
file, err := f.FetchByName(addNodesParamsFile)
66+
if err != nil {
67+
if os.IsNotExist(err) {
68+
return false, nil
69+
}
70+
return false, fmt.Errorf("failed to load %s file: %w", addNodesParamsFile, err)
71+
}
72+
73+
params := &Params{}
74+
if err := json.Unmarshal(file.Data, params); err != nil {
75+
return false, fmt.Errorf("failed to unmarshal %s: %w", addNodesParamsFile, err)
76+
}
77+
78+
a.Params = *params
79+
return true, nil
80+
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package joiner
2+
3+
import (
4+
"context"
5+
"net/url"
6+
7+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8+
"k8s.io/client-go/kubernetes"
9+
"k8s.io/client-go/rest"
10+
"k8s.io/client-go/tools/clientcmd"
11+
12+
configclient "github.com/openshift/client-go/config/clientset/versioned"
13+
"github.com/openshift/installer/pkg/asset"
14+
"github.com/openshift/installer/pkg/asset/agent/workflow"
15+
)
16+
17+
// ClusterInfo it's an asset used to retrieve config info
18+
// from an already existing cluster.
19+
type ClusterInfo struct {
20+
ClusterID string
21+
APIDNSName string
22+
PullSecret string
23+
}
24+
25+
var _ asset.WritableAsset = (*ClusterInfo)(nil)
26+
27+
// Name returns the human-friendly name of the asset.
28+
func (ci *ClusterInfo) Name() string {
29+
return "Agent Installer ClusterInfo"
30+
}
31+
32+
// Dependencies returns all of the dependencies directly needed to generate
33+
// the asset.
34+
func (*ClusterInfo) Dependencies() []asset.Asset {
35+
return []asset.Asset{
36+
&workflow.AgentWorkflow{},
37+
&AddNodesConfig{},
38+
}
39+
}
40+
41+
// Generate generates the ClusterInfo.
42+
func (ci *ClusterInfo) Generate(dependencies asset.Parents) error {
43+
agentWorkflow := &workflow.AgentWorkflow{}
44+
addNodesConfig := &AddNodesConfig{}
45+
dependencies.Get(agentWorkflow, addNodesConfig)
46+
47+
if agentWorkflow.Workflow != workflow.AgentWorkflowTypeAddNodes {
48+
return nil
49+
}
50+
51+
config, err := ci.getRestConfig(addNodesConfig.Params.Kubeconfig)
52+
if err != nil {
53+
return err
54+
}
55+
56+
err = ci.retrieveClusterID(config)
57+
if err != nil {
58+
return err
59+
}
60+
61+
err = ci.retrieveAPIDNSName(config)
62+
if err != nil {
63+
return err
64+
}
65+
66+
err = ci.retrievePullSecret(config)
67+
if err != nil {
68+
return err
69+
}
70+
71+
return nil
72+
}
73+
74+
func (ci *ClusterInfo) getRestConfig(kubeconfig string) (*rest.Config, error) {
75+
var err error
76+
var config *rest.Config
77+
78+
if kubeconfig != "" {
79+
config, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
80+
} else {
81+
config, err = rest.InClusterConfig()
82+
}
83+
84+
return config, err
85+
}
86+
87+
func (ci *ClusterInfo) retrieveClusterID(config *rest.Config) error {
88+
clientset, err := configclient.NewForConfig(config)
89+
if err != nil {
90+
return err
91+
}
92+
93+
cv, err := clientset.ConfigV1().ClusterVersions().Get(context.Background(), "version", metav1.GetOptions{})
94+
if err != nil {
95+
return err
96+
}
97+
ci.ClusterID = string(cv.Spec.ClusterID)
98+
99+
return nil
100+
}
101+
102+
func (ci *ClusterInfo) retrieveAPIDNSName(config *rest.Config) error {
103+
parsedURL, err := url.Parse(config.Host)
104+
if err != nil {
105+
return err
106+
}
107+
108+
ci.APIDNSName = parsedURL.Hostname()
109+
return nil
110+
}
111+
112+
func (ci *ClusterInfo) retrievePullSecret(config *rest.Config) error {
113+
clientset, err := kubernetes.NewForConfig(config)
114+
if err != nil {
115+
return err
116+
}
117+
118+
pullSecret, err := clientset.CoreV1().Secrets("openshift-config").Get(context.Background(), "pull-secret", metav1.GetOptions{})
119+
if err != nil {
120+
return err
121+
}
122+
ci.PullSecret = string(pullSecret.Data[".dockerconfigjson"])
123+
124+
return nil
125+
}
126+
127+
// Files returns the files generated by the asset.
128+
func (*ClusterInfo) Files() []*asset.File {
129+
return []*asset.File{}
130+
}
131+
132+
// Load returns agent config asset from the disk.
133+
func (*ClusterInfo) Load(f asset.FileFetcher) (bool, error) {
134+
return false, nil
135+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package workflow
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/openshift/installer/pkg/asset"
8+
)
9+
10+
// AgentWorkflow allows other assets to check
11+
// which is the workflow currently active.
12+
type AgentWorkflow struct {
13+
File *asset.File
14+
Workflow AgentWorkflowType
15+
}
16+
17+
var _ asset.WritableAsset = (*AgentWorkflow)(nil)
18+
19+
// Name returns a human friendly name for the asset.
20+
func (*AgentWorkflow) Name() string {
21+
return "Agent Workflow"
22+
}
23+
24+
// Dependencies returns all of the dependencies directly needed to generate
25+
// the asset.
26+
func (*AgentWorkflow) Dependencies() []asset.Asset {
27+
return []asset.Asset{}
28+
}
29+
30+
// Generate generates the AgentWorkflow asset.
31+
func (a *AgentWorkflow) Generate(dependencies asset.Parents) error {
32+
// Set install workflow as a default
33+
a.Workflow = AgentWorkflowTypeInstall
34+
a.File = &asset.File{
35+
Filename: agentWorkflowFilename,
36+
Data: []byte(a.Workflow),
37+
}
38+
39+
return nil
40+
}
41+
42+
// Files returns the files generated by the asset.
43+
func (a *AgentWorkflow) Files() []*asset.File {
44+
if a.File != nil {
45+
return []*asset.File{a.File}
46+
}
47+
return []*asset.File{}
48+
}
49+
50+
// Load returns the asset from disk.
51+
func (a *AgentWorkflow) Load(f asset.FileFetcher) (bool, error) {
52+
file, err := f.FetchByName(agentWorkflowFilename)
53+
if err != nil {
54+
if os.IsNotExist(err) {
55+
return false, nil
56+
}
57+
return false, fmt.Errorf("failed to load %s file: %w", agentWorkflowFilename, err)
58+
}
59+
60+
// Get the current workflow
61+
a.Workflow = AgentWorkflowType(file.Data)
62+
a.File = file
63+
64+
return true, nil
65+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package workflow
2+
3+
import "github.com/openshift/installer/pkg/asset"
4+
5+
// AgentWorkflowAddNodes is meant just to define
6+
// the add nodes workflow.
7+
type AgentWorkflowAddNodes struct {
8+
AgentWorkflow
9+
}
10+
11+
var _ asset.WritableAsset = (*AgentWorkflowAddNodes)(nil)
12+
13+
// Name returns a human friendly name for the asset.
14+
func (*AgentWorkflowAddNodes) Name() string {
15+
return "Agent Workflow Add Nodes"
16+
}
17+
18+
// Generate generates the AgentWorkflow asset.
19+
func (a *AgentWorkflowAddNodes) Generate(dependencies asset.Parents) error {
20+
a.Workflow = AgentWorkflowTypeAddNodes
21+
a.File = &asset.File{
22+
Filename: agentWorkflowFilename,
23+
Data: []byte(a.Workflow),
24+
}
25+
26+
return nil
27+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package workflow
2+
3+
// AgentWorkflowType defines the supported
4+
// agent workflows.
5+
type AgentWorkflowType string
6+
7+
const (
8+
// AgentWorkflowTypeInstall identifies the install workflow.
9+
AgentWorkflowTypeInstall AgentWorkflowType = "install"
10+
// AgentWorkflowTypeAddNodes identifies the add nodes workflow.
11+
AgentWorkflowTypeAddNodes AgentWorkflowType = "addnodes"
12+
13+
agentWorkflowFilename = ".agentworkflow"
14+
)

pkg/nodejoiner/addnodes.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,26 @@ package nodejoiner
22

33
import (
44
"github.com/openshift/installer/pkg/asset"
5+
"github.com/openshift/installer/pkg/asset/agent/joiner"
6+
"github.com/openshift/installer/pkg/asset/agent/workflow"
57
"github.com/openshift/installer/pkg/asset/store"
68
)
79

810
// NewAddNodesCommand creates a new command for add nodes.
9-
func NewAddNodesCommand(directory string) error {
11+
func NewAddNodesCommand(directory string, kubeConfig string) error {
12+
// Store the current parameters into the assets folder, so
13+
// that they could be retrieved later by the assets
14+
params := joiner.Params{
15+
Kubeconfig: kubeConfig,
16+
}
17+
err := params.Save(directory)
18+
if err != nil {
19+
return err
20+
}
21+
1022
fetcher := store.NewAssetsFetcher(directory)
11-
return fetcher.FetchAndPersist([]asset.WritableAsset{})
23+
return fetcher.FetchAndPersist([]asset.WritableAsset{
24+
&workflow.AgentWorkflowAddNodes{},
25+
// To be completed
26+
})
1227
}

0 commit comments

Comments
 (0)