-
Notifications
You must be signed in to change notification settings - Fork 44
Expand file tree
/
Copy pathnodeAdd.py
More file actions
executable file
·168 lines (135 loc) · 5.4 KB
/
nodeAdd.py
File metadata and controls
executable file
·168 lines (135 loc) · 5.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#!/usr/bin/env python
"""Add Node to Cluster"""
### usage:
### ./nodeAdd.py -v 10.1.1.211 -u admin # will choose a free node that is in the same chassis
### ./nodeAdd.py -v 10.1.1.211 -u admin -n nodeID # will try to use free node with specified ID
### ./nodeAdd.py -v 10.1.1.211 -u admin -i 10.0.0.12 -p 10.0.0.13 # provide IP and IPMI addresses
# or will use existing addresses
### import pyhesity wrapper module
from pyhesity import *
### command line arguments
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-s', '--server', type=str, required=True)
parser.add_argument('-u', '--username', type=str, required=True)
parser.add_argument('-d', '--domain', type=str, default='local')
parser.add_argument('-n', '--nodeId', type=int, default=0)
parser.add_argument('-i', '--ipAddress', type=str, default='')
parser.add_argument('-p', '--ipmiAddress', type=str, default='')
parser.add_argument('-v', '--newVip', type=str, default='')
args = parser.parse_args()
server = args.server
username = args.username
domain = args.domain
nodeId = args.nodeId
ipAddress = args.ipAddress
ipmiAddress = args.ipmiAddress
newVip = args.newVip
### ip validate functions
def ipToBinary(ip):
return ''.join(['{0:08b}'.format(int(octet)) for octet in ip.split('.')])
def ipValid(newIp, oldIp, netMask):
cidr = ipToBinary(netMask).index('0')
if('1' not in ipToBinary(newIp)[cidr:]):
return False
if('0' not in ipToBinary(newIp)[cidr:]):
return False
return ipToBinary(newIp)[0:cidr] == ipToBinary(oldIp)[0:cidr]
### authenticate
apiauth(server, username, domain)
### get cluster config
clusterStat = api('get', '/nexus/cluster/status')
chassisList = []
for chassis in clusterStat['clusterConfig']['proto']['chassisVec']:
chassisList.append(chassis['name'])
### get free nodes
freeNodes = api('get', '/nexus/avahi/discover_nodes')
selectedNode = 0
foundNode = 0
for node in freeNodes['freeNodes']:
if foundNode == 0:
foundNode = node
if nodeId == 0:
### see if node is in one of our chassis
if(node['chassisSerial'] in chassisList):
selectedNode = node
break
else:
### see if this is the node specified from the commandLine
if(node['nodeId'] == nodeId):
print("using %i" % node['nodeId'])
selectedNode = node
break
# if no node was specified and no node was in the same chassis, use the first available node
if nodeId == 0 and selectedNode == 0 and foundNode != 0:
selectedNode = foundNode
# if node was specified but not found, fail
if selectedNode == 0:
print("Couldn't find node with ID: %i" % nodeId)
exit()
else:
### gather cluster subnet details
clusterSubnet = clusterStat['clusterConfig']['proto']['clusterSubnet']['ip']
clusterNetMask = clusterStat['clusterConfig']['proto']['clusterSubnet']['netmaskIp4']
ipmiSubnet = clusterStat['clusterConfig']['proto']['ipmiConfig']['subnet']['ip']
ipmiNetMask = clusterStat['clusterConfig']['proto']['ipmiConfig']['subnet']['netmaskIp4']
### validate VIP
partitions = api('get', 'clusterPartitions')
if(newVip == ''):
createVip = False
if(len(partitions[0]['nodeIds']) >= len(partitions[0]['vips'])):
print("please provide a new VIP")
exit()
else:
createVip = True
if(not ipValid(newVip, clusterSubnet, clusterNetMask)):
print("VIP address %s is not in the range of the cluster subnet %s(%s)" % (newVip, clusterSubnet, clusterNetMask))
exit()
if(newVip in partitions[0]['vips']):
print("VIP %s is already in use on the cluster. Please select an unused address" % newVip)
exit()
### validate Node IP
if ipAddress == '':
if 'ipAddresses' in selectedNode:
ipAddress = selectedNode['ipAddresses'][0]
else:
print("please provide node ip Address")
exit()
if(not ipValid(ipAddress, clusterSubnet, clusterNetMask)):
print("Node IPAddress %s is not in range of the cluster subnet %s(%s)" % (ipAddress, clusterSubnet, clusterNetMask))
exit()
### validate ipmi IP
if ipmiAddress == '':
if 'ipmiIp' in selectedNode and selectedNode['ipmiIp'] != '':
ipmiAddress = selectedNode['ipmiIp']
else:
print("please provide ipmi ip address")
exit()
if(not ipValid(ipmiAddress, ipmiSubnet, ipmiNetMask)):
print("Node ipmi address %s is not in range of the ipmi subnet %s(%s)" % (ipmiAddress, ipmiSubnet, ipmiNetMask))
exit()
### new node parameters
newNodeParams = {
"nodes": [
{
"id": selectedNode['nodeId'],
"ip": ipAddress,
"ipmiIp": ipmiAddress
}
],
"clusterPartitionId": clusterStat['clusterConfig']['proto']['clusterPartitionVec'][0]['id'],
"autoUpdate": True,
"ignoreSwIncompatibility": True
}
### add the vip
if(createVip):
print("adding VIP %s" % newVip)
partitions[0]['vips'].append(newVip)
vipresult = api('put', '/clusterPartitions/%i' % partitions[0]['id'], partitions[0])
### execute the node add
print("Adding node %i to cluster" % selectedNode['nodeId'])
result = api('post', '/nexus/cluster/expand', newNodeParams)
if 'message' in result:
print(result['message'])
else:
display(result)