Skip to content

Commit 0e15fa6

Browse files
Merge pull request #304 from openshift-cherrypick-robot/cherry-pick-287-to-18.0-fr2
[18.0-fr2] Refactor provision_ip_discovery.go
2 parents bb09889 + 8be21b5 commit 0e15fa6

File tree

1 file changed

+94
-133
lines changed

1 file changed

+94
-133
lines changed

containers/agent/provision_ip_discovery.go

Lines changed: 94 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -41,173 +41,134 @@ func init() {
4141
}
4242

4343
func runProvisionIPStartCmd(_ *cobra.Command, _ []string) {
44-
var err error
45-
err = flag.Set("logtostderr", "true")
46-
if err != nil {
44+
// Setup logging
45+
if err := flag.Set("logtostderr", "true"); err != nil {
4746
panic(err.Error())
4847
}
49-
5048
flag.Parse()
51-
5249
glog.V(0).Info("Starting ProvisionIpDiscoveryAgent")
5350

54-
if provisionIPStartOpts.provIntf == "" {
55-
name, ok := os.LookupEnv("PROV_INTF")
56-
if !ok || name == "" {
57-
glog.Fatalf("prov-intf is required")
58-
}
59-
provisionIPStartOpts.provIntf = name
51+
// Set required environment variables or fail gracefully
52+
provisionIPStartOpts.provIntf = getEnvOrFail("PROV_INTF", provisionIPStartOpts.provIntf)
53+
provisionIPStartOpts.provServerName = getEnvOrFail("PROV_SERVER_NAME", provisionIPStartOpts.provServerName)
54+
provisionIPStartOpts.provServerNamespace = getEnvOrFail("PROV_SERVER_NAMESPACE", provisionIPStartOpts.provServerNamespace)
55+
56+
// Kubernetes client setup
57+
config, err := getKubeConfig()
58+
if err != nil {
59+
panic(err.Error())
6060
}
6161

62-
if provisionIPStartOpts.provServerName == "" {
63-
name, ok := os.LookupEnv("PROV_SERVER_NAME")
64-
if !ok || name == "" {
65-
glog.Fatalf("prov-server-name is required")
62+
dClient := dynamic.NewForConfigOrDie(config)
63+
provServerClient := dClient.Resource(openstackProvisionServerGVR)
64+
65+
var ip string
66+
for {
67+
curIP, intfFound := getInterfaceIP(provisionIPStartOpts.provIntf)
68+
if curIP == "" || curIP != ip {
69+
err := updateProvisioningStatus(provServerClient, curIP, intfFound)
70+
if err != nil {
71+
glog.V(0).Infof("Error updating OpenStackProvisionServer %s (namespace %s) status: %s",
72+
provisionIPStartOpts.provServerName, provisionIPStartOpts.provServerNamespace, err)
73+
// Set ip to empty string as we've to update provisonserver in the next try
74+
ip = ""
75+
} else {
76+
ip = curIP
77+
}
6678
}
67-
provisionIPStartOpts.provServerName = name
79+
time.Sleep(time.Second * 5)
6880
}
81+
}
6982

70-
if provisionIPStartOpts.provServerNamespace == "" {
71-
name, ok := os.LookupEnv("PROV_SERVER_NAMESPACE")
72-
if !ok || name == "" {
73-
glog.Fatalf("prov-server-namespace is required")
83+
// getEnvOrFail retrieves an environment variable or returns a default value, failing if the value is empty.
84+
func getEnvOrFail(envVar, defaultValue string) string {
85+
if defaultValue == "" {
86+
val, ok := os.LookupEnv(envVar)
87+
if !ok || val == "" {
88+
glog.Fatalf("%s is required", envVar)
7489
}
75-
provisionIPStartOpts.provServerNamespace = name
90+
return val
7691
}
92+
return defaultValue
93+
}
7794

78-
var config *rest.Config
95+
// getKubeConfig returns the Kubernetes configuration, either from the provided KUBECONFIG environment variable or from the cluster.
96+
func getKubeConfig() (*rest.Config, error) {
7997
kubeconfig := os.Getenv("KUBECONFIG")
8098
if kubeconfig != "" {
81-
config, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
82-
} else {
83-
// creates the in-cluster config
84-
config, err = rest.InClusterConfig()
99+
return clientcmd.BuildConfigFromFlags("", kubeconfig)
85100
}
101+
return rest.InClusterConfig()
102+
}
86103

104+
// getInterfaceIP returns the IP address for the given interface, or an empty string if not found.
105+
func getInterfaceIP(interfaceName string) (string, bool) {
106+
ifaces, err := net.Interfaces()
87107
if err != nil {
88108
panic(err.Error())
89109
}
90110

91-
dClient := dynamic.NewForConfigOrDie(config)
92-
93-
provServerClient := dClient.Resource(openstackProvisionServerGVR)
94-
95-
ip := ""
96-
97-
// Get provision interface IP and update the status, and then sleep 5 seconds
98-
// and check again over and over (because the IP address could change)
99-
for {
100-
ifaces, err := net.Interfaces()
101-
102-
if err != nil {
103-
panic(err.Error())
104-
}
105-
106-
curIP := ""
107-
intfFound := false
108-
109-
for _, iface := range ifaces {
110-
if iface.Name == provisionIPStartOpts.provIntf {
111-
intfFound = true
112-
113-
addrs, err := iface.Addrs()
114-
115-
if err != nil {
116-
panic(err.Error())
117-
}
118-
119-
for _, addr := range addrs {
120-
ipObj, _, err := net.ParseCIDR(addr.String())
121-
122-
if err != nil || ipObj == nil {
123-
glog.V(0).Infof("WARNING: Cannot parse IP address for OpenStackProvisionServer %s (namespace %s) on interface %s!\n", provisionIPStartOpts.provServerName, provisionIPStartOpts.provServerName, provisionIPStartOpts.provIntf)
124-
if err != nil {
125-
glog.V(0).Infof("ERROR: %s", err.Error())
126-
}
127-
continue
128-
}
129-
130-
if ipObj = ipObj.To4(); ipObj != nil {
131-
curIP = ipObj.String()
132-
break
133-
}
134-
glog.V(0).Infof("INFO: Ignoring IPv6 address (%s) for OpenStackProvisionServer %s (namespace %s) on interface %s!\n", addr, provisionIPStartOpts.provServerName, provisionIPStartOpts.provServerName, provisionIPStartOpts.provIntf)
135-
}
136-
break
137-
}
138-
}
139-
140-
if curIP == "" || ip != curIP {
141-
unstructured, err := provServerClient.Namespace(provisionIPStartOpts.provServerNamespace).Get(context.Background(), provisionIPStartOpts.provServerName, metav1.GetOptions{}, "/status")
142-
143-
if k8s_errors.IsNotFound(err) {
144-
// Deleted somehow, so just break
145-
break
146-
}
111+
intfFound := false
147112

113+
for _, iface := range ifaces {
114+
if iface.Name == interfaceName {
115+
intfFound = true
116+
addrs, err := iface.Addrs()
148117
if err != nil {
149118
panic(err.Error())
150119
}
151120

152-
if unstructured.Object["status"] == nil {
153-
unstructured.Object["status"] = map[string]interface{}{}
154-
}
155-
156-
status := unstructured.Object["status"].(map[string]interface{})
157-
158-
if curIP == "" {
159-
var errMsg string // shorter message intended for surfacing in OpenStackProvisionServer CR
160-
var errMsgFull string // longer message for provisiong agent pod logs
161-
162-
if intfFound {
163-
// Missing IP
164-
errMsg = fmt.Sprintf("Unable to find provisioning IP on interface %s", provisionIPStartOpts.provIntf)
165-
errMsgFull = fmt.Sprintf("%s for OpenStackProvisionServer %s (namespace %s)\n", errMsg, provisionIPStartOpts.provServerName, provisionIPStartOpts.provServerNamespace)
166-
} else {
167-
// Missing interface entirely
168-
errMsg = fmt.Sprintf("Unable to find provisioning interface %s", provisionIPStartOpts.provIntf)
169-
errMsgFull = fmt.Sprintf("%s for OpenStackProvisionServer %s (namespace %s)\n", errMsg, provisionIPStartOpts.provServerName, provisionIPStartOpts.provServerNamespace)
121+
for _, addr := range addrs {
122+
ipObj, _, err := net.ParseCIDR(addr.String())
123+
if err != nil || ipObj == nil {
124+
glog.V(0).Infof("WARNING: Cannot parse IP address for interface %s: %v", interfaceName, err)
125+
continue
170126
}
171127

172-
glog.V(0).Infof("ERROR: %s", errMsgFull)
173-
174-
status["provisionIpError"] = errMsg
175-
176-
unstructured.Object["status"] = status
177-
178-
_, err = provServerClient.Namespace(provisionIPStartOpts.provServerNamespace).UpdateStatus(context.Background(), unstructured, metav1.UpdateOptions{})
179-
180-
if err != nil {
181-
glog.V(0).Infof("Error updating OpenStackProvisionServer %s (namespace %s) status with provisioning IP acquisition error: %s\n",
182-
provisionIPStartOpts.provServerName, provisionIPStartOpts.provServerNamespace,
183-
err)
184-
} else {
185-
glog.V(0).Infof("Updated OpenStackProvisionServer %s (namespace %s) status with provisioning IP acquisition error\n",
186-
provisionIPStartOpts.provServerName,
187-
provisionIPStartOpts.provServerNamespace)
188-
128+
if ipObj = ipObj.To4(); ipObj != nil {
129+
return ipObj.String(), intfFound
189130
}
190-
} else {
191-
// ip != curIP case
192-
status["provisionIp"] = curIP
193-
status["provisionIpError"] = ""
194-
195-
unstructured.Object["status"] = status
131+
glog.V(0).Infof("INFO: Ignoring IPv6 address (%s) on interface %s", addr, interfaceName)
132+
}
133+
}
134+
}
135+
return "", intfFound
136+
}
196137

197-
_, err = provServerClient.Namespace(provisionIPStartOpts.provServerNamespace).UpdateStatus(context.Background(), unstructured, metav1.UpdateOptions{})
138+
// updateProvisioningStatus updates the provisioning status in Kubernetes with the given IP and error status.
139+
func updateProvisioningStatus(provServerClient dynamic.NamespaceableResourceInterface, curIP string, intfFound bool) error {
140+
unstructured, err := provServerClient.Namespace(provisionIPStartOpts.provServerNamespace).Get(context.Background(), provisionIPStartOpts.provServerName, metav1.GetOptions{}, "/status")
141+
if k8s_errors.IsNotFound(err) {
142+
// Server deleted, stop the loop
143+
return nil
144+
}
145+
if err != nil {
146+
return err
147+
}
198148

199-
if err != nil {
200-
glog.V(0).Infof("Error updating OpenStackProvisionServer %s (namespace %s) \"provisionIp\" status: %s\n", provisionIPStartOpts.provServerName, provisionIPStartOpts.provServerNamespace, err)
201-
} else {
202-
ip = curIP
203-
glog.V(0).Infof("Updated OpenStackProvisionServer %s (namespace %s) with status \"provisionIp\": %s\n", provisionIPStartOpts.provServerName, provisionIPStartOpts.provServerNamespace, ip)
149+
if unstructured.Object["status"] == nil {
150+
unstructured.Object["status"] = map[string]interface{}{}
151+
}
204152

205-
}
206-
}
153+
status := unstructured.Object["status"].(map[string]interface{})
154+
if curIP == "" {
155+
var errMsg, errMsgFull string
156+
if intfFound {
157+
errMsg = fmt.Sprintf("Unable to find provisioning IP on interface %s", provisionIPStartOpts.provIntf)
158+
} else {
159+
errMsg = fmt.Sprintf("Unable to find provisioning interface %s", provisionIPStartOpts.provIntf)
207160
}
161+
errMsgFull = fmt.Sprintf("%s for OpenStackProvisionServer %s (namespace %s)", errMsg, provisionIPStartOpts.provServerName, provisionIPStartOpts.provServerNamespace)
162+
glog.V(0).Infof("ERROR: %s", errMsgFull)
208163

209-
time.Sleep(time.Second * 5)
164+
status["provisionIp"] = ""
165+
status["provisionIpError"] = errMsg
166+
} else {
167+
status["provisionIp"] = curIP
168+
status["provisionIpError"] = ""
210169
}
211170

212-
glog.V(0).Info("Shutting down ProvisionIpDiscoveryAgent")
171+
unstructured.Object["status"] = status
172+
_, err = provServerClient.Namespace(provisionIPStartOpts.provServerNamespace).UpdateStatus(context.Background(), unstructured, metav1.UpdateOptions{})
173+
return err
213174
}

0 commit comments

Comments
 (0)