Auto: Daily job definition
[releng.git] / utils / lab-reconfiguration / reconfigUcsNet.py
1 #!/usr/bin/python
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #  http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 # This script reconfigure UCSM vnics for varios OPNFV deployers
15 # Usage: reconfigUcsNet.py [options]
16 #
17 # Options:
18 # -h, --help            show this help message and exit
19 # -i IP, --ip=IP        [Mandatory] UCSM IP Address
20 # -u USERNAME, --username=USERNAME
21 #                       [Mandatory] Account Username for UCSM Login
22 # -p PASSWORD, --password=PASSWORD
23 #                       [Mandatory] Account Password for UCSM Login
24 # -f FILE, --file=FILE
25 #                       [Optional] Yaml file with network config you
26 #                       want to set for POD
27 #                       If not present only current network config
28 #                       will be printed
29 #
30
31 import getpass
32 import optparse
33 import platform
34 import yaml
35 import time
36 import sys
37 from UcsSdk import LsmaintAck, LsPower, LsServer, OrgOrg
38 from UcsSdk import UcsHandle, VnicEther, VnicEtherIf, YesOrNo
39
40
41 POD_PREFIX = "POD-2"
42 INSTALLER = "POD-21"
43
44
45 def getpassword(prompt):
46     if platform.system() == "Linux":
47         return getpass.unix_getpass(prompt=prompt)
48     elif platform.system() == "Windows" or platform.system() == "Microsoft":
49         return getpass.win_getpass(prompt=prompt)
50     else:
51         return getpass.getpass(prompt=prompt)
52
53
54 def get_servers(handle=None):
55     """
56     Return list of servers
57     """
58     orgObj = handle.GetManagedObject(
59         None, OrgOrg.ClassId(), {OrgOrg.DN: "org-root"})[0]
60     servers = handle.GetManagedObject(orgObj, LsServer.ClassId())
61     for server in servers:
62         if server.Type == 'instance' and POD_PREFIX in server.Dn:
63             yield server
64
65
66 def set_boot_policy(handle=None, server=None, policy=None):
67     """
68     Modify Boot policy of server
69     """
70     obj = handle.GetManagedObject(None, LsServer.ClassId(), {
71         LsServer.DN: server.Dn})
72     handle.SetManagedObject(obj, LsServer.ClassId(), {
73         LsServer.BOOT_POLICY_NAME: policy})
74     print(" Configured boot policy: {}".format(policy))
75
76
77 def ack_pending(handle=None, server=None):
78     """
79     Acknowledge pending state of server
80     """
81     handle.AddManagedObject(server, LsmaintAck.ClassId(), {
82         LsmaintAck.DN: server.Dn + "/ack",
83         LsmaintAck.DESCR: "",
84         LsmaintAck.ADMIN_STATE: "trigger-immediate",
85         LsmaintAck.SCHEDULER: "",
86         LsmaintAck.POLICY_OWNER: "local"}, True)
87     print(" Pending-reboot -> Acknowledged.")
88
89
90 def boot_server(handle=None, server=None):
91     """
92     Boot server (when is in power-off state)
93     """
94     obj = handle.GetManagedObject(
95         None, LsServer.ClassId(), {LsServer.DN: server.Dn})
96     handle.AddManagedObject(obj, LsPower.ClassId(), {
97         LsPower.DN: server.Dn + "/power",
98         LsPower.STATE: "admin-up"}, True)
99     print(" Booting.")
100
101
102 def get_vnics(handle=None, server=None):
103     """
104     Return list of vnics for given server
105     """
106     vnics = handle.ConfigResolveChildren(
107         VnicEther.ClassId(), server.Dn, None, YesOrNo.TRUE)
108     return vnics.OutConfigs.GetChild()
109
110
111 def get_network_config(handle=None):
112     """
113     Print current network config
114     """
115     print("\nCURRENT NETWORK CONFIG:")
116     print(" d - default, t - tagged")
117     for server in get_servers(handle):
118         print(' {}'.format(server.Name))
119         print('  Boot policy: {}'.format(server.OperBootPolicyName))
120         for vnic in get_vnics(handle, server):
121             print('  {}'.format(vnic.Name))
122             print('   {}'.format(vnic.Addr))
123             vnicIfs = handle.ConfigResolveChildren(
124                 VnicEtherIf.ClassId(), vnic.Dn, None, YesOrNo.TRUE)
125             for vnicIf in vnicIfs.OutConfigs.GetChild():
126                 if vnicIf.DefaultNet == 'yes':
127                     print('    Vlan: {}d'.format(vnicIf.Vnet))
128                 else:
129                     print('    Vlan: {}t'.format(vnicIf.Vnet))
130
131
132 def add_interface(handle=None,
133                   lsServerDn=None,
134                   vnicEther=None,
135                   templName=None,
136                   order=None,
137                   macAddr=None):
138     """
139     Add interface to server specified by server.DN name
140     """
141     print(" Adding interface: {}, template: {}, server.Dn: {}".format(
142         vnicEther, templName, lsServerDn))
143     obj = handle.GetManagedObject(
144         None, LsServer.ClassId(), {LsServer.DN: lsServerDn})
145     vnicEtherDn = lsServerDn + "/ether-" + vnicEther
146     params = {
147         VnicEther.STATS_POLICY_NAME: "default",
148         VnicEther.NAME: vnicEther,
149         VnicEther.DN: vnicEtherDn,
150         VnicEther.SWITCH_ID: "A-B",
151         VnicEther.ORDER: order,
152         "adminHostPort": "ANY",
153         VnicEther.ADMIN_VCON: "any",
154         VnicEther.ADDR: macAddr,
155         VnicEther.NW_TEMPL_NAME: templName,
156         VnicEther.MTU: "1500"}
157     handle.AddManagedObject(obj, VnicEther.ClassId(), params, True)
158
159
160 def remove_interface(handle=None, vnicEtherDn=None):
161     """
162     Remove interface specified by Distinguished Name (vnicEtherDn)
163     """
164     print(" Removing interface: {}".format(vnicEtherDn))
165     obj = handle.GetManagedObject(
166         None, VnicEther.ClassId(), {VnicEther.DN: vnicEtherDn})
167     handle.RemoveManagedObject(obj)
168
169
170 def read_yaml_file(yamlFile):
171     """
172     Read vnic config from yaml file
173     """
174     # TODO: add check if vnic templates specified in file exist on UCS
175     with open(yamlFile, 'r') as stream:
176         return yaml.safe_load(stream)
177
178
179 def set_network(handle=None, yamlFile=None):
180     """
181     Configure VLANs on POD according specified network
182     """
183     # add interfaces and bind them with vNIC templates
184     print("\nRECONFIGURING VNICs...")
185     pod_data = read_yaml_file(yamlFile)
186     network = pod_data['network']
187
188     for index, server in enumerate(get_servers(handle)):
189         # Assign template to interface
190         for iface, data in network.iteritems():
191             add_interface(handle, server.Dn, iface, data['template'], data[
192                           'order'], data['mac-list'][index])
193
194         # Remove other interfaces which have not assigned required vnic
195         # template
196         vnics = get_vnics(handle, server)
197         for vnic in vnics:
198             if not any(data['template'] in vnic.OperNwTemplName for
199                        iface, data in network.iteritems()):
200                 remove_interface(handle, vnic.Dn)
201                 print("  {} removed, template: {}".format(
202                     vnic.Name, vnic.OperNwTemplName))
203
204         # Set boot policy template
205         if INSTALLER not in server.Dn:
206             set_boot_policy(handle, server, pod_data['boot-policy'])
207
208
209 if __name__ == "__main__":
210     print("\n*** SKIPING RECONFIGURATION.***\n")
211     sys.exit(0)
212     # Latest urllib2 validate certs by default
213     # The process wide "revert to the old behaviour" hook is to monkeypatch
214     # the ssl module
215     # https://bugs.python.org/issue22417
216     import ssl
217     if hasattr(ssl, '_create_unverified_context'):
218         ssl._create_default_https_context = ssl._create_unverified_context
219     try:
220         handle = UcsHandle()
221         parser = optparse.OptionParser()
222         parser.add_option('-i', '--ip', dest="ip",
223                           help="[Mandatory] UCSM IP Address")
224         parser.add_option('-u', '--username', dest="userName",
225                           help="[Mandatory] Account Username for UCSM Login")
226         parser.add_option('-p', '--password', dest="password",
227                           help="[Mandatory] Account Password for UCSM Login")
228         parser.add_option('-f', '--file', dest="yamlFile",
229                           help=("[Optional] Yaml file contains network "
230                                 "config you want to set on UCS POD1"))
231         (options, args) = parser.parse_args()
232
233         if not options.ip:
234             parser.print_help()
235             parser.error("Provide UCSM IP Address")
236         if not options.userName:
237             parser.print_help()
238             parser.error("Provide UCSM UserName")
239         if not options.password:
240             options.password = getpassword("UCSM Password:")
241
242         handle.Login(options.ip, options.userName, options.password)
243
244         # Change vnic template if specified in cli option
245         if (options.yamlFile is not None):
246             set_network(handle, options.yamlFile)
247             time.sleep(5)
248
249         print("\nWait until Overall Status of all nodes is OK...")
250         timeout = time.time() + 60 * 10  # 10 minutes timeout
251         while True:
252             list_of_states = []
253             for server in get_servers(handle):
254                 if server.OperState == "power-off":
255                     boot_server(handle, server)
256                 if server.OperState == "pending-reboot":
257                     ack_pending(handle, server)
258                 list_of_states.append(server.OperState)
259             print(" {}, {} seconds remains.".format(
260                 list_of_states, round(timeout - time.time())))
261             if all(state == "ok" for state in list_of_states):
262                 break
263             if time.time() > timeout:
264                 raise Exception("Timeout reached while waiting for OK status.")
265             time.sleep(10)
266
267         # Show current vnic MACs and VLANs
268         get_network_config(handle)
269
270         handle.Logout()
271
272     except Exception as err:
273         handle.Logout()
274         print("Exception:", str(err))
275         import traceback
276         import sys
277         print('-' * 60)
278         traceback.print_exc(file=sys.stdout)
279         print('-' * 60)
280         sys.exit(1)