def get_netscaler_entities_for_type(self, resource_type, _retries=0): if _retries == MAX_NITRO_RETRIES: self.logger.debug("Failed to connect to Netscaler after several retries") raise ImplementationErrorException("The Load Balancing Service is misbehaving." + " Please contact support") path_prefix = self.conn.path url = path_prefix + "/" + resource_type headers = {'Cookie': "sessionid=" + self.conn.sessionid} status, response = self._nitro_perform_http_request('GET', url, headers) if status == "SESSION_EXPIRED": """ login sessionid to Netscaler expired. Relogin and retry the call""" self.nitro_login() return self.get_netscaler_entities_for_type(resource_type, _retries + 1) """ XXX - This is to get around a NITRO bug which doesn't return an empty list when there are no entities. Instead it omits the element completely. """ if not resource_type in response: state_list = [] else: state_list = response[resource_type] self.logger.debug("response object=%s" % str(state_list)) return state_list
def get_netscaler_updatehealthmonitor_tasks(self, loadBalancerId, loadBalancer, healthMonitor): task_list = [] """ Let's first find out if there is already a monitor for this load balancer """ monitor = self._get_netscaler_loadBalancer_monitor( loadBalancerId, loadBalancer) if monitor == None: return self.get_netscaler_addhealthmonitor_tasks( loadBalancerId, loadBalancer, healthMonitor) if not monitor["type"] == "TCP" and not monitor["type"] == "USER": self.logger.debug("We expect only TCP or USER monitor. Found: %s" % monitor["type"]) raise ImplementationErrorException("programming error") """ This loadBalancer has already got a health monitor. """ tasks = self._get_netscaler_updatemonitor_tasks( loadBalancerId, loadBalancer, healthMonitor) if tasks: task_list.extend(tasks) return task_list
def _get_netscaler_tasks_for_remove_op(self, loadBalancerId, loadBalancer): task_list = [] if not loadBalancerId: raise ImplementationErrorException("Programming error") self.logger.debug( "Getting all tasks to remove resources of loadbalancer") task = self._get_netscaler_removeloadbalancer_task(loadBalancerId) task_list.append(task) tasks = self._get_netscaler_removenodes_tasks(loadBalancerId, loadBalancer) task_list.extend(tasks) tasks = self._get_netscaler_removehealthmonitor_tasks( loadBalancerId, loadBalancer) task_list.extend(tasks) """ XXX - We should also remove other resources. """ """ logging_tasks = self._get_netscaler_removeconnectionlogging_tasks(loadBalancer, lbvserver) task_list.extend(logging_tasks) throttle_tasks = self._get_netscaler_removeconnectionthrottle_tasks(loadBalancer, lbvserver) task_list.extend(throttle_tasks) """ return task_list
def _get_netscaler_tasks_for_get_op(self, loadBalancerId): task_list = [] if not loadBalancerId: raise ImplementationErrorException("Programming error") task = NitroTasks.get_netscaler_getlbvserver_task(loadBalancerId) task_list.append(task) tasks = self._get_netscaler_getnodes_tasks(loadBalancerId) task_list.extend(tasks) tasks = self._get_netscaler_gethealthmonitor_tasks(loadBalancerId) """ We don't care if there is no healthmonitor set on the load balancer """ if tasks: for task in tasks: task["ignore_notfound"] = True task_list.extend(tasks) """ XXX - We should get all info about the loadbalancer, e.g. connection logging, etc. """ """ logging_tasks = self._get_netscaler_getlogging_tasks(loadBalancer, lbvserver) task_list.extend(logging_tasks) throttle_tasks = self._get_netscaler_getthrottle_tasks(loadBalancer, lbvserver) task_list.extend(throttle_tasks) """ return task_list
def _get_netscaler_tasks_for_add_op(self, loadBalancerId, loadBalancer): task_list = [] if not all([loadBalancerId, loadBalancer]): raise ImplementationErrorException("Programming error") task = self._get_netscaler_addloadbalancer_task( loadBalancerId, loadBalancer) task_list.append(task) lbvserver = task["state"] nodes_tasks = self._get_netscaler_addnodes_tasks( loadBalancerId, loadBalancer) task_list.extend(nodes_tasks) monitor_tasks = self._get_netscaler_addhealthmonitor_tasks( loadBalancerId, loadBalancer) task_list.extend(monitor_tasks) logging_tasks = self._get_netscaler_addconnectionlogging_tasks( loadBalancerId, loadBalancer) task_list.extend(logging_tasks) throttle_tasks = self._get_netscaler_addconnectionthrottle_tasks( loadBalancerId, loadBalancer) task_list.extend(throttle_tasks) return task_list
def validate_virtualIP_object_for_add(self, virtualIP): errors = [] self.lbresource.logger.debug("virtualIP object to validate: %s" % virtualIP) self.lbresource.logger.debug("type of virtualIP object: %s" % str(type(virtualIP))) if virtualIP == None: raise ImplementationErrorException("programming error") if "ipVersion" in virtualIP: error = "ipVersion property not a valid property of virtualIP" errors.append(error) if "address" in virtualIP: error = "address property not a valid property of virtualIP" errors.append(error) if "id" in virtualIP and ("type" in virtualIP): error = "id property cannot be used with type properties of virtualIP" errors.append(error) if not "type" in virtualIP and not "id" in virtualIP: error = "type or id property of virtualIP must be specified" errors.append(error) if "type" in virtualIP: error = self.validate_type_value(virtualIP) if error: errors.append(error) return errors
def _nitro_disable_netscaler_entity(self, resource_type, resource_state, _retries=0): if _retries == MAX_NITRO_RETRIES: self.logger.debug("Failed to connect to Netscaler after several retries") raise ImplementationErrorException("The Load Balancing Service is misbehaving." + " Please contact support") path_prefix = self.conn.path url = path_prefix headers = {'Content-Type':'application/x-www-form-urlencoded'} params_part = "\"params\":{\"action\":\"disable\"}" sessionid_part = "\"sessionid\":\"" + self.conn.sessionid + "\"" self.logger.debug("disable task state: " + str(resource_state)) entity_part = NitroUtils.get_entity_payload_from_dictobj(resource_type, resource_state) self.logger.debug("disable body: " + str(entity_part)) body= "{" + params_part + "," + sessionid_part + "," + entity_part + "}" body = "object=" + body status, response = self._nitro_perform_http_request('POST', url, headers, body) if status == "SESSION_EXPIRED": """ login sessionid to Netscaler expired. Relogin and retry the call""" self.nitro_login() return self._nitro_disable_netscaler_entity(resource_type, resource_state, _retries + 1)
def _get_service_payload_from_dictobj(dictobj): if not "name" in dictobj.keys(): raise ImplementationErrorException("programming error") payload = "\"service\":{" payload += "\"name\":\"" + dictobj["name"] + "\"" if "servicetype" in dictobj.keys(): servicetype = dictobj["servicetype"] payload += "," payload += "\"servicetype\":\"" + servicetype + "\"" if "ip" in dictobj.keys(): ip = dictobj["ip"] payload += "," payload += "\"ip\":\"" + ip + "\"" if "port" in dictobj.keys(): port = dictobj["port"] payload += "," payload += "\"port\":\"" + str(port) + "\"" if "newname" in dictobj.keys(): newname = dictobj["newname"] payload += "," payload += "\"newname\":\"" + newname + "\"" payload += "}" return payload
def _get_netscaler_tasks_for_update_op(self, loadBalancerId, loadBalancer, nodeId, node): if not node: raise ImplementationErrorException("Programming error") task_list = self._get_netscaler_updatenode_tasks(loadBalancerId, loadBalancer, nodeId, node) return task_list
def get_nspersistencetype_from_persistencetype(persistencetype): if persistencetype == "HTTP_COOKIE": return "COOKIEINSERT" if persistencetype == "SOURCE_IP": return "SOURCEIP" """ We should never get another value than the above values """ raise ImplementationErrorException("programming error")
def get_algorithm_from_lbmethod(lbmethod): if lbmethod == "LEASTCONNECTION": return "LEAST_CONNECTIONS" if lbmethod == "ROUNDROBIN": return "ROUND_ROBIN" """ We should never get another lbmethod than the above values """ raise ImplementationErrorException("programming error")
def get_loadbalancerstatus_from_state(state): if state == "UP": return "ACTIVE" if state == "DOWN": return "SUSPENDED" """ We should never get another value than the above values """ raise ImplementationErrorException("programming error")
def get_nssureconnect_from_sureconnect(sureconnect): if sureconnect == "true": return "ON" if sureconnect == "false": return "OFF" """ We should never get another value than the above values """ raise ImplementationErrorException("programming error")
def _get_monitorbinding_payload_from_dictobj(dictobj): if not "monitorname" in dictobj.keys(): raise ImplementationErrorException("programming error") payload = "\"lbmonitor_service_binding\":{" payload += "\"monitorname\":\"" + dictobj["monitorname"] + "\"" if not "servicename" in dictobj.keys(): raise ImplementationErrorException("programming error") servicename = dictobj["servicename"] payload += "," payload += "\"servicename\":\"" + servicename + "\"" payload += "}" return payload
def get_condition_from_svrstate(svrstate): svrstate = svrstate.encode('ascii', 'ignore') if svrstate.find("OUT OF SERVICE") != -1: return "DISABLED" else: return "ENABLED" """ We should never get another value than the above values """ raise ImplementationErrorException("programming error")
def get_nodestatus_from_svrstate(svrstate): svrstate = svrstate.encode('ascii', 'ignore') if svrstate == "UP": return "ONLINE" else: return "OFFLINE" """ We should never get another value than the above values """ raise ImplementationErrorException("programming error")
def generate_id(maxid, minid=0, used_ids=None): if used_ids and len(used_ids) >= maxid: raise ImplementationErrorException("programming error") newid = random.randrange(minid, maxid) while newid in used_ids: newid = random.randrange(minid, maxid) return newid
def _nitro_parse_response_body(self, response_body): try: resp_dict = json.loads(response_body) except TypeError: self.logger.error("Failed to get a valid response from Netscaler: Response body: %s" % response_body) raise ImplementationErrorException("Programming error") return resp_dict
def _get_netscaler_tasks_for_list_op(self, loadBalancerId, loadBalancer): task_list = [] if not loadBalancerId: raise ImplementationErrorException("Programming error") task = self.get_netscaler_getservicebindings_task(loadBalancerId, loadBalancer) task_list.append(task) return task_list
def _get_netscaler_tasks_for_remove_op(self, loadBalancerId, loadBalancer): task_list = [] if not all([loadBalancerId, loadBalancer]): raise ImplementationErrorException("Programming error") tasks = self.get_netscaler_removehealthmonitor_tasks( loadBalancerId, loadBalancer) task_list.extend(tasks) return task_list
def _nitro_check_for_errors(self, response_object): if not ('errorcode' in response_object.keys()) or not('message' in response_object.keys()): self.logger.error("Nitro Response body doesn't contain errorcode and/or message") raise ImplementationErrorException("programming error.") errorcode = response_object["errorcode"] errormessage = response_object["message"] self.logger.debug("errorcode=%s" % errorcode) self.logger.debug("message=%s" % errormessage) if errorcode == 444: return "SESSION_EXPIRED" if errorcode == 258 or errorcode == 344: self.logger.debug("Netscaler entity not found: %s " % errormessage) raise ItemNotFoundException("resource not found") if errorcode == 273 or errorcode == 2305 or errorcode == 304: self.logger.debug("Netscaler entity already exists: %s" % errormessage) raise BadRequestException("Logic fault", "resource already exists with these settings") if errorcode == 257: self.logger.debug("Very likely to be the wrong session persistence setting for this lb protocol: %s" % errormessage) raise BadRequestException("Logic fault", "session persistence persistenceType not compatible with protocol") if errorcode == 1097: self.logger.debug("Invalid argument for Netscaler entity: %s" % errormessage) raise BadRequestException("Validation fault", "invalid value for attribute", errormessage) if errorcode == 1075: self.logger.debug("Invalid argument for Netscaler entity: %s" % errormessage) """ chop-off the name portion of the message, so as not to reveal how we are mapping names. """ index = errormessage.find('[') if index != -1: errormessage = errormessage[:index] raise BadRequestException("Validation fault", "invalid value for attribute", errormessage) if errorcode == 1110: self.logger.debug("Invalid IP address for Netscaler entity: %s" % errormessage) raise BadRequestException("Validation fault", "invalid value for attribute", "Invalid IP address") """ Catch all check """ if errorcode != 0: self.logger.debug("Nitro Response error code unknown: %d" % errorcode) raise BadRequestException("Unknown Error", "Error with request", "This request caused an error and cannot be fulfilled.") return "SUCCESS"
def _get_netscaler_tasks_for_update_op(self, loadBalancerId, loadBalancer, healthMonitor): if not healthMonitor: raise ImplementationErrorException("Programming error") self._validate_healthmonitor(loadBalancerId, loadBalancer, healthMonitor) task_list = self.get_netscaler_updatehealthmonitor_tasks( loadBalancerId, loadBalancer, healthMonitor) return task_list
def _get_netscaler_tasks_for_remove_op(self, loadBalancerId, loadBalancer, nodeId): task_list = [] if not all([loadBalancerId, loadBalancer, nodeId]): raise ImplementationErrorException("Programming error") task = self.get_netscaler_removeservicebinding_task(loadBalancerId, loadBalancer, nodeId) task_list.append(task) task = self._get_netscaler_removeservice_task(loadBalancerId, loadBalancer, nodeId) task_list.append(task) return task_list
def _http_get_response_body(self, method, host, port, path, headers, body): connection = httplib.HTTPConnection(host, port=port) connection.request(method, path, body=body, headers=headers) response = connection.getresponse() self.logger.debug("status=%d" % response.status) if response.status != 200: self.logger.debug("Error: HTTP status code unexpected: %s" + response.status) raise ImplementationErrorException("The Load Balancing Service is misbehaving." + " Please contact support") return response.read()
def get_persistencetype_from_nspersistencetype(nspersistencetype): nspersistencetype = nspersistencetype.encode('ascii', 'ignore') if nspersistencetype == "COOKIEINSERT": return "HTTP_COOKIE" if nspersistencetype == "SOURCEIP": return "SOURCE_IP" if nspersistencetype == "NONE": return None """ We should never get another value than the above values """ raise ImplementationErrorException("programming error")
def get_response_body(objectname, objectvalue, context): if objectvalue == None: self.logger.debug( "objectvalue is None, so cannot generate response body...Not expecting this !! " ) raise ImplementationErrorException("programming error") payload = get_payload_from_object(objectname, objectvalue, context.response_format, context.logger, context.lbservice.plurals, context.xmlnamespace) return payload
def _get_servicebinding_payload_from_dictobj(dictobj): if not "name" in dictobj.keys(): raise ImplementationErrorException("programming error") payload = "\"lbvserver_service_binding\":{" payload += "\"name\":\"" + dictobj["name"] + "\"" if not "servicename" in dictobj.keys(): raise ImplementationErrorException("programming error") servicename = dictobj["servicename"] payload += "," payload += "\"servicename\":\"" + servicename + "\"" if "weight" in dictobj.keys(): weight = dictobj["weight"] payload += "," payload += "\"weight\":\"" + weight + "\"" payload += "}" return payload
def get_protocol_from_servicetype(servicetype): if servicetype == "HTTP": return "HTTP" if servicetype == "SSL": return "HTTPS" if servicetype == "TCP": return "TCP" if servicetype == "TCP-SSL": return "TCP-SSL" """ We should never get another lbmethod than the above values """ raise ImplementationErrorException("programming error")
def _get_monitor_payload_from_dictobj(dictobj): if not "monitorname" in dictobj.keys(): raise ImplementationErrorException("programming error") payload = "\"lbmonitor\":{" payload += "\"monitorname\":\"" + dictobj["monitorname"] + "\"" if "type" in dictobj.keys(): montype = dictobj["type"] payload += "," payload += "\"type\":\"" + montype + "\"" if "interval" in dictobj.keys(): interval = dictobj["interval"] payload += "," payload += "\"interval\":\"" + str(interval) + "\"" if "resptimeout" in dictobj.keys(): resptimeout = dictobj["resptimeout"] payload += "," payload += "\"resptimeout\":\"" + str(resptimeout) + "\"" if "retries" in dictobj.keys(): retries = dictobj["retries"] payload += "," payload += "\"retries\":\"" + str(retries) + "\"" if "scriptname" in dictobj.keys(): scriptname = dictobj["scriptname"] payload += "," payload += "\"scriptname\":\"" + scriptname + "\"" if "scriptargs" in dictobj.keys(): scriptargs = dictobj["scriptargs"] payload += "," payload += "\"scriptargs\":\"" + scriptargs + "\"" payload += "}" return payload
def get_lbmethod_from_algorithm(algorithm): if algorithm == "LEAST_CONNECTIONS": return "LEASTCONNECTION" if algorithm == "WEIGHTED_LEAST_CONNECTIONS": return "LEASTCONNECTION" if algorithm == "ROUND_ROBIN": return "ROUNDROBIN" if algorithm == "WEIGHTED_ROUND_ROBIN": return "ROUNDROBIN" if algorithm == "RANDOM": raise NotImplementedException( "Sorry, this loadBalancer service currently doesn't implement the LB algorithm %s" % algorithm) """ We should never get another lbmethod than the above values """ raise ImplementationErrorException("programming error")