def name(self): if self._values['name'] is None: return None if not is_valid_fqdn(self._values['name']): raise F5ModuleError("The provided name must be a valid FQDN") return self._values['name']
def parent(self): if self.want.parent != self.have.parent: raise F5ModuleError("The parent http profile cannot be changed")
def parent(self): if self.want.parent != self.have.parent: raise F5ModuleError("The parent monitor cannot be changed")
def partition(self): raise F5ModuleError( "Partition cannot be changed for a traffic group. Only /Common is allowed." )
def cert_key_chains(self): result = [] if self.client_ssl_profile is None: return None if 'cert_key_chain' not in self.client_ssl_profile: return None kc = self.client_ssl_profile['cert_key_chain'] if isinstance(kc, string_types) and kc != 'inherit': raise F5ModuleError( "Only the 'inherit' setting is available when 'cert_key_chain' is a string." ) if not isinstance(kc, list): raise F5ModuleError( "The value of 'cert_key_chain' is not one of the supported types." ) cert_references = self._get_cert_references() key_references = self._get_key_references() for idx, x in enumerate(kc): tmp = dict( name='clientssl{0}'.format(idx) ) if 'cert' not in x: raise F5ModuleError( "A 'cert' option is required when specifying the 'cert_key_chain' parameter.." ) elif x['cert'] not in cert_references: raise F5ModuleError( "The specified 'cert' was not found. Did you specify its full path?" ) else: key = x['cert'] tmp['certReference'] = dict( link=cert_references[key], fullPath=key ) if 'key' not in x: raise F5ModuleError( "A 'key' option is required when specifying the 'cert_key_chain' parameter.." ) elif x['key'] not in key_references: raise F5ModuleError( "The specified 'key' was not found. Did you specify its full path?" ) else: key = x['key'] tmp['keyReference'] = dict( link=key_references[key], fullPath=key ) if 'chain' in x and x['chain'] not in cert_references: raise F5ModuleError( "The specified 'key' was not found. Did you specify its full path?" ) else: key = x['chain'] tmp['chainReference'] = dict( link=cert_references[key], fullPath=key ) if 'passphrase' in x: tmp['passphrase'] = x['passphrase'] result.append(tmp) return result
def _handle_weight(self, weight): if weight < 10 or weight > 100: raise F5ModuleError( "Weight value must be in the range: '10 - 100'.") return weight
def download(self): self.download_from_device() if os.path.exists(self.want.dest): return True raise F5ModuleError("Failed to download the remote file")
def port(self): if self._values['port'] is None: return None if 0 <= self._values['port'] <= 65535: return self._values['port'] raise F5ModuleError("Valid 'port' must be in range 0 - 65535.")
def destination_address(self): result = self._format_address('destination_address') if result == -1: raise F5ModuleError( "No IP address found in 'destination_address'.") return result
def device_address(self): if is_valid_ip(self._values['device_address']): return self._values['device_address'] raise F5ModuleError( 'Provided device address: {0} is not a valid IP.'.format( self._values['device_address']))
def access_group_name(self): if self.want.access_group_name != self.have.access_group_name: raise F5ModuleError( 'Access group name cannot be modified once it is set.')
def upload_file(client, url, src, dest=None): """Upload a file to an arbitrary URL. This method is responsible for correctly chunking an upload request to an arbitrary file worker URL. Arguments: client (object): The F5RestClient connection object. url (string): The URL to upload a file to. src (string): The file to be uploaded. dest (string): The file name to create on the remote device. Examples: The ``dest`` may be either an absolute or relative path. The basename of the path is used as the remote file name upon upload. For instance, in the example below, ``BIGIP-13.1.0.8-0.0.3.iso`` would be the name of the remote file. The specified URL should be the full URL to where you want to upload a file. BIG-IP has many different URLs that can be used to handle different types of files. This is why a full URL is required. >>> from ansible.module_utils.network.f5.icontrol import upload_client >>> url = 'https://{0}:{1}/mgmt/cm/autodeploy/software-image-uploads'.format( ... self.client.provider['server'], ... self.client.provider['server_port'] ... ) >>> dest = '/path/to/BIGIP-13.1.0.8-0.0.3.iso' >>> upload_file(self.client, url, dest) True Returns: bool: True on success. False otherwise. Raises: F5ModuleError: Raised if ``retries`` limit is exceeded. """ if isinstance(src, StringIO) or isinstance(src, BytesIO): fileobj = src else: fileobj = open(src, 'rb') try: size = os.stat(src).st_size is_file = True except TypeError: src.seek(0, os.SEEK_END) size = src.tell() src.seek(0) is_file = False # This appears to be the largest chunk size that iControlREST can handle. # # The trade-off you are making by choosing a chunk size is speed, over size of # transmission. A lower chunk size will be slower because a smaller amount of # data is read from disk and sent via HTTP. Lots of disk reads are slower and # There is overhead in sending the request to the BIG-IP. # # Larger chunk sizes are faster because more data is read from disk in one # go, and therefore more data is transmitted to the BIG-IP in one HTTP request. # # If you are transmitting over a slow link though, it may be more reliable to # transmit many small chunks that fewer large chunks. It will clearly take # longer, but it may be more robust. chunk_size = 1024 * 7168 start = 0 retries = 0 if dest is None and is_file: basename = os.path.basename(src) else: basename = dest url = '{0}/{1}'.format(url.rstrip('/'), basename) while True: if retries == 3: # Retries are used here to allow the REST API to recover if you kill # an upload mid-transfer. # # There exists a case where retrying a new upload will result in the # API returning the POSTed payload (in bytes) with a non-200 response # code. # # Retrying (after seeking back to 0) seems to resolve this problem. raise F5ModuleError("Failed to upload file too many times.") try: file_slice = fileobj.read(chunk_size) if not file_slice: break current_bytes = len(file_slice) if current_bytes < chunk_size: end = size else: end = start + current_bytes headers = { 'Content-Range': '%s-%s/%s' % (start, end - 1, size), 'Content-Type': 'application/octet-stream' } # Data should always be sent using the ``data`` keyword and not the # ``json`` keyword. This allows bytes to be sent (such as in the case # of uploading ISO files. response = client.api.post(url, headers=headers, data=file_slice) if response.status != 200: # When this fails, the output is usually the body of whatever you # POSTed. This is almost always unreadable because it is a series # of bytes. # # Therefore, including an empty exception here. raise F5ModuleError() start += current_bytes except F5ModuleError: # You must seek back to the beginning of the file upon exception. # # If this is not done, then you risk uploading a partial file. fileobj.seek(0) retries += 1 return True
def absent(self): raise F5ModuleError( "The 'local' type cannot be removed. " "Instead, specify a 'state' of 'present' on other types.")
def __init__(self, content=None): self.raw_content = content try: self.content = xml.etree.ElementTree.fromstring(content) except xml.etree.ElementTree.ParseError as ex: raise F5ModuleError("Provided XML payload is invalid. Received '{0}'.".format(str(ex)))
def create_from_file(self): task = self.import_to_device() if not task: return False if not self.wait_for_task(task): raise F5ModuleError('Import policy task failed.')
def source_address(self): result = self._format_address('source_address') if result == -1: raise F5ModuleError("No IP address found in 'source_address'.") return result
def type(self): if self.want.type != self.have.type: raise F5ModuleError("'type' cannot be changed once it is set.")
def ip_ttl_v6(self): if self._values['ip_ttl_v6'] is None: return None if 0 <= self._values['ip_ttl_v6'] <= 255: return int(self._values['ip_ttl_v6']) raise F5ModuleError('ip_ttl_v6 must be between 0 and 255')
def update(self): if os.path.exists(self.want.fulldest): if not self.want.force: raise F5ModuleError("File '{0}' already exists".format( self.want.fulldest)) self.execute()
def link_qos_to_server(self): result = self.transform_link_qos('link_qos_to_server') if result == -1: raise F5ModuleError('link_qos_to_server must be between 0 and 7') return result
def profile(self): if self.want.profile is None: return None if self.want.profile != self.have.profile: raise F5ModuleError("'profile' cannot be changed after it is set.")
def _validate_conn_limit(self, limit): if limit is None: return None if 0 <= int(limit) <= 65535: return int(limit) raise F5ModuleError("Valid 'maximum_age' must be in range 0 - 65535.")
def parent(self): if self.want.parent is None: return None if self.want.parent != self.have.parent: raise F5ModuleError("The parent router profile cannot be changed.")
def ratio(self): if self._values['ratio'] is None: return None if 0 <= self._values['ratio'] <= 4294967295: return self._values['ratio'] raise F5ModuleError("Valid 'ratio' must be in range 0 - 4294967295.")
def check_bigiq_version(self): version = bigiq_version(self.client) if LooseVersion(version) >= LooseVersion('6.1.0'): raise F5ModuleError( 'Module supports only BIGIQ version 6.0.x or lower.' )
def mtu(self): if self._values['mtu'] is None: return None if int(self._values['mtu']) < 576 or int(self._values['mtu']) > 9198: raise F5ModuleError("The mtu value must be between 576 - 9198") return int(self._values['mtu'])
def interval(self): if self._values['interval'] is None: return None if 1 > int(self._values['interval']) > 86400: raise F5ModuleError("Interval value must be between 1 and 86400") return int(self._values['interval'])
def _get_validated_ip_address(self, address): if is_valid_ip(self._values[address]): return self._values[address] raise F5ModuleError( "The specified '{0}' is not a valid IP address".format(address))
def network(self): if self.want.network is None: return None if self.want.network != self.have.network: raise F5ModuleError("'network' cannot be changed after it is set.")
def _test_subnet(self, item): if item is None: return None if is_valid_ip_network(item): return item raise F5ModuleError("Specified 'subnet' is not a valid subnet.")