@@ -41,173 +41,134 @@ func init() {
4141}
4242
4343func 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