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