signature:
def read ( cls , data , protocol = None , fallback_protocol = TBinaryProtocol , finagle_thrift = False , max_fields = MAX_FIELDS , max_list_size = MAX_LIST_SIZE , max_map_size = MAX_MAP_SIZE , max_set_size = MAX_SET_SIZE , read_values = False ) :
    """tries to deserialize a message , might fail if data is missing"""

implementation:
# do we have enough data ?
if len ( data ) < cls . MIN_MESSAGE_SIZE :
    raise ValueError ( 'not enough data' )
if protocol is None :
    protocol = cls . detect_protocol ( data , fallback_protocol )
trans = TTransport . TMemoryBuffer ( data )
proto = protocol ( trans )
# finagle - thrift prepends a RequestHeader
# See : http : / / git . io / vsziG
header = None
if finagle_thrift :
    try :
        header = ThriftStruct . read ( proto , max_fields , max_list_size , max_map_size , max_set_size , read_values )
    except : # reset stream , maybe it ' s not finagle - thrift
        trans = TTransport . TMemoryBuffer ( data )
        proto = protocol ( trans )
# unpack the message
method , mtype , seqid = proto . readMessageBegin ( )
mtype = cls . message_type_to_str ( mtype )
if len ( method ) == 0 or method . isspace ( ) or method . startswith ( ' ' ) :
    raise ValueError ( 'no method name' )
if len ( method ) > cls . MAX_METHOD_LENGTH :
    raise ValueError ( 'method name too long' )
# we might have made it until this point by mere chance , so filter out
# suspicious method names
valid = range ( 33 , 127 )
if any ( ord ( char ) not in valid for char in method ) :
    raise ValueError ( 'invalid method name' % method )
args = ThriftStruct . read ( proto , max_fields , max_list_size , max_map_size , max_set_size , read_values )
proto . readMessageEnd ( )
# Note : this is a bit fragile , the right thing would be to count bytes
# as we read them ( i . e . : when calling readI32 , etc ) .
msglen = trans . _buffer . tell ( )
return cls ( method , mtype , seqid , args , header , msglen ) , msglen


signature:
def detect_protocol ( cls , data , default = None ) :
    """TODO : support fbthrift , finagle - thrift , finagle - mux , CORBA"""

implementation:
if cls . is_compact_protocol ( data ) :
    return TCompactProtocol
elif cls . is_binary_protocol ( data ) :
    return TBinaryProtocol
elif cls . is_json_protocol ( data ) :
    return TJSONProtocol
if default is None :
    raise ValueError ( 'Unknown protocol' )
return default


signature:
def pop ( self , nbytes ) :
    """pops packets with _ at least _ nbytes of payload"""

implementation:
size = 0
popped = [ ]
with self . _lock_packets :
    while size < nbytes :
        try :
            packet = self . _packets . pop ( 0 )
            size += len ( packet . data . data )
            self . _remaining -= len ( packet . data . data )
            popped . append ( packet )
        except IndexError :
            break
return popped


signature:
def pop_data ( self , nbytes ) :
    """similar to pop , but returns payload + last timestamp"""

implementation:
last_timestamp = 0
data = [ ]
for packet in self . pop ( nbytes ) :
    last_timestamp = packet . timestamp
    data . append ( packet . data . data )
return '' . join ( data ) , last_timestamp


signature:
def push ( self , ip_packet ) :
    """push the packet into the queue"""

implementation:
data_len = len ( ip_packet . data . data )
seq_id = ip_packet . data . seq
if data_len == 0 :
    self . _next_seq_id = seq_id
    return False
# have we seen this packet ?
if self . _next_seq_id != - 1 and seq_id != self . _next_seq_id :
    return False
self . _next_seq_id = seq_id + data_len
with self . _lock_packets : # Note : we only account for payload ( i . e . : tcp data )
    self . _length += len ( ip_packet . data . data )
    self . _remaining += len ( ip_packet . data . data )
    self . _packets . append ( ip_packet )
return True


signature:
def run ( self , * args , ** kwargs ) :
    """Deal with the incoming packets"""

implementation:
while True :
    try :
        timestamp , ip_p = self . _queue . popleft ( )
        src_ip = get_ip ( ip_p , ip_p . src )
        dst_ip = get_ip ( ip_p , ip_p . dst )
        src = intern ( '%s:%s' % ( src_ip , ip_p . data . sport ) )
        dst = intern ( '%s:%s' % ( dst_ip , ip_p . data . dport ) )
        key = intern ( '%s<->%s' % ( src , dst ) )
        stream = self . _streams . get ( key )
        if stream is None :
            stream = Stream ( src , dst )
            self . _streams [ key ] = stream
        # HACK : save the timestamp
        setattr ( ip_p , 'timestamp' , timestamp )
        pushed = stream . push ( ip_p )
        if not pushed :
            continue
        # let listeners know about the updated stream
        for handler in self . _handlers :
            try :
                handler ( stream )
            except Exception as ex :
                print ( 'handler exception: %s' % ex )
    except Exception :
        time . sleep ( 0.00001 )


signature:
def getLogin ( filename , user , passwd ) :
    '''write user / passwd to login file or get them from file .
 This method is not Py3 safe ( byte vs . str )'''

implementation:
if filename is None :
    return ( user , passwd )
isPy2 = sys . version_info [ 0 ] == 2
if os . path . exists ( filename ) :
    print ( "Using file {} for Login" . format ( filename ) )
    with open ( filename , "r" ) as loginfile :
        encoded_cred = loginfile . read ( )
        print ( "encoded: {}" . format ( encoded_cred ) )
        if isPy2 :
            decoded_cred = b64decode ( encoded_cred )
        else :
            decoded_cred = b64decode ( encoded_cred ) . decode ( 'utf-8' )
        login = decoded_cred . split ( ':' , 1 )
        return ( login [ 0 ] , login [ 1 ] )
else :
    if user is None or passwd is None :
        raise ValueError ( "user and password must not be None" )
    print ( "Writing file {} for Login" . format ( filename ) )
    with open ( filename , "wb" ) as loginfile :
        creds = user + ":" + passwd
        if isPy2 :
            encoded_cred = b64encode ( creds )
        else :
            encoded_cred = b64encode ( creds . encode ( 'utf-8' ) )
        print ( "encoded: {}" . format ( encoded_cred ) )
        loginfile . write ( encoded_cred )
    return ( user , passwd )


signature:
def wait_for_requests ( pbclient , request_ids = None , timeout = 0 , initial_wait = 5 , scaleup = 10 ) :
    '''Waits for a list of requests to finish until timeout .
 timeout = = 0 is interpreted as infinite wait time .
 Returns a dict of request _ id - > result .
 result is a tuple ( return code , request status , message ) where return code
 0 : request successful
 1 : request failed
 -1 : timeout exceeded
 The wait _ period is increased every scaleup steps to adjust for long
 running requests .'''

implementation:
done = dict ( )
if not request_ids :
    print ( "empty request list" )
    return done
total_wait = 0
wait_period = initial_wait
next_scaleup = scaleup * wait_period
wait = True
while wait :
    for request_id in request_ids :
        if request_id in done :
            continue
        request_status = pbclient . get_request ( request_id , status = True )
        state = request_status [ 'metadata' ] [ 'status' ]
        if state == "DONE" :
            done [ request_id ] = ( 0 , state , request_status [ 'metadata' ] [ 'message' ] )
            print ( "Request '{}' is in state '{}'." . format ( request_id , state ) )
        if state == 'FAILED' :
            done [ request_id ] = ( 1 , state , request_status [ 'metadata' ] [ 'message' ] )
            print ( "Request '{}' is in state '{}'." . format ( request_id , state ) )
    # end for ( request _ ids )
    if len ( done ) == len ( request_ids ) :
        wait = False
    else :
        print ( "{} of {} requests are finished. Sleeping for {} seconds..." . format ( len ( done ) , len ( request_ids ) , wait_period ) )
        sleep ( wait_period )
        total_wait += wait_period
        if timeout != 0 and total_wait > timeout :
            wait = False
        next_scaleup -= wait_period
        if next_scaleup == 0 :
            wait_period += initial_wait
            next_scaleup = scaleup * wait_period
            print ( "scaling up wait_period to {}, next change in {} seconds" . format ( wait_period , next_scaleup ) )
    # end if / else ( done )
# end while ( wait )
if len ( done ) != len ( request_ids ) :
    for request_id in request_ids :
        if request_id in done :
            continue
        done [ request_id ] = ( - 1 , state , "request not finished before timeout" )
return done


signature:
def get_disk_image_by_name ( pbclient , location , image_name ) :
    """Returns all disk images within a location with a given image name .
 The name must match exactly .
 The list may be empty ."""

implementation:
all_images = pbclient . list_images ( )
matching = [ i for i in all_images [ 'items' ] if i [ 'properties' ] [ 'name' ] == image_name and i [ 'properties' ] [ 'imageType' ] == "HDD" and i [ 'properties' ] [ 'location' ] == location ]
return matching


signature:
def main ( argv = None ) :
    '''Command line options .'''

implementation:
if argv is None :
    argv = sys . argv
else :
    sys . argv . extend ( argv )
program_name = os . path . basename ( sys . argv [ 0 ] )
program_version = "v%s" % __version__
program_build_date = str ( __updated__ )
program_version_message = '%%(prog)s %s (%s)' % ( program_version , program_build_date )
program_shortdesc = __import__ ( '__main__' ) . __doc__ . split ( "\n" ) [ 1 ]
program_license = '''%s

  Created by Jürgen Buchhammer on %s.
  Copyright 2016 ProfitBricks GmbH. All rights reserved.

  Licensed under the Apache License 2.0
  http://www.apache.org/licenses/LICENSE-2.0

  Distributed on an "AS IS" basis without warranties
  or conditions of any kind, either express or implied.

USAGE
''' % ( program_shortdesc , str ( __date__ ) )
try : # Setup argument parser
    parser = ArgumentParser ( description = program_license , formatter_class = RawDescriptionHelpFormatter )
    parser . add_argument ( '-u' , '--user' , dest = 'user' , help = 'the login name' )
    parser . add_argument ( '-p' , '--password' , dest = 'password' , help = 'the login password' )
    parser . add_argument ( '-L' , '--Login' , dest = 'loginfile' , default = None , help = 'the login file to use' )
    parser . add_argument ( '-t' , '--type' , dest = 'metatype' , default = "OVF" , help = 'type of VM meta data' )
    parser . add_argument ( '-m' , '--metadata' , dest = 'metafile' , required = True , default = None , help = 'meta data file' )
    parser . add_argument ( '-d' , '--datacenterid' , dest = 'datacenterid' , default = None , help = 'datacenter of the new server' )
    parser . add_argument ( '-D' , '--DCname' , dest = 'dcname' , default = None , help = 'new datacenter name' )
    parser . add_argument ( '-l' , '--location' , dest = 'location' , default = None , help = 'location for new datacenter' )
    parser . add_argument ( '-v' , '--verbose' , dest = "verbose" , action = "count" , default = 0 , help = "set verbosity level [default: %(default)s]" )
    parser . add_argument ( '-V' , '--version' , action = 'version' , version = program_version_message )
    # Process arguments
    args = parser . parse_args ( )
    global verbose
    verbose = args . verbose
    if verbose > 0 :
        print ( "Verbose mode on" )
        print ( "start {} with args {}" . format ( program_name , str ( args ) ) )
    ( user , password ) = getLogin ( args . loginfile , args . user , args . password )
    if user is None or password is None :
        raise ValueError ( "user or password resolved to None" )
    pbclient = ProfitBricksService ( user , password )
    if args . metatype == 'OVF' :
        metadata = OFVData ( args . metafile )
        metadata . parse ( )
    else :
        sys . stderr . write ( "Metadata type '{}' is not supported" . format ( args . metatype ) )
        return 1
    # we need the DC first to have the location defined
    dc_id = None
    if args . datacenterid is None :
        if args . dcname is None or args . location is None :
            sys . stderr . write ( "Either '-d <id>' or '-D <name> -l <loc>'  must be specified" )
            return 1
        # else : we will create the DC later after parsing the meta data
    else :
        dc_id = args . datacenterid
    if dc_id is None :
        location = args . location
        dc = Datacenter ( name = args . dcname , location = location , description = "created by pb_importVM" )
        print ( "create new DC {}" . format ( str ( dc ) ) )
        response = pbclient . create_datacenter ( dc )
        dc_id = response [ 'id' ]
        result = wait_for_request ( pbclient , response [ 'requestId' ] )
        print ( "wait loop returned {}" . format ( result ) )
    else :
        dc = pbclient . get_datacenter ( dc_id )
        location = dc [ 'properties' ] [ 'location' ]
        print ( "use existing DC {} in location {}" . format ( dc [ 'properties' ] [ 'name' ] , location ) )
    # check if images exist
    for disk in metadata . disks :
        disk_name = disk [ 'file' ]
        images = get_disk_image_by_name ( pbclient , location , disk_name )
        if not images :
            raise ValueError ( "No HDD image with name '{}' found in location {}" . format ( disk_name , location ) )
        if len ( images ) > 1 :
            raise ValueError ( "Ambigous image name '{}' in location {}" . format ( disk_name , location ) )
        disk [ 'image' ] = images [ 0 ] [ 'id' ]
    # now we ' re ready to create the VM
    # Server
    server = Server ( name = metadata . name , cores = metadata . cpus , ram = metadata . ram )
    print ( "create server {}" . format ( str ( Server ) ) )
    response = pbclient . create_server ( dc_id , server )
    srv_id = response [ 'id' ]
    result = wait_for_request ( pbclient , response [ 'requestId' ] )
    print ( "wait loop returned {}" . format ( str ( result ) ) )
    # NICs ( note that createing LANs may be implicit )
    for nic in metadata . nics :
        dcnic = NIC ( name = nic [ 'nic' ] , lan = nic [ 'lanid' ] )
        print ( "create NIC {}" . format ( str ( dcnic ) ) )
        response = pbclient . create_nic ( dc_id , srv_id , dcnic )
        nic_id = response [ 'id' ]
        result = wait_for_request ( pbclient , response [ 'requestId' ] )
        print ( "wait loop returned {}" . format ( str ( result ) ) )
        response = pbclient . get_nic ( dc_id , srv_id , nic_id , 2 )
        mac = response [ 'properties' ] [ 'mac' ]
        print ( "dcnic has MAC {} for {}" . format ( mac , nic_id ) )
    # end for ( nics )
    # Volumes ( we use the image name as volume name too
    requests = [ ]
    for disk in metadata . disks :
        dcvol = Volume ( name = disk [ 'file' ] , size = disk [ 'capacity' ] , image = disk [ 'image' ] , licence_type = metadata . licenseType )
        print ( "create Volume {}" . format ( str ( dcvol ) ) )
        response = pbclient . create_volume ( dc_id , dcvol )
        requests . append ( response [ 'requestId' ] )
        disk [ 'volume_id' ] = response [ 'id' ]
    # end for ( disks )
    if requests :
        result = wait_for_requests ( pbclient , requests , initial_wait = 10 , scaleup = 15 )
        print ( "wait loop returned {}" . format ( str ( result ) ) )
    for disk in metadata . disks :
        print ( "attach volume {}" . format ( disk ) )
        response = pbclient . attach_volume ( dc_id , srv_id , disk [ 'volume_id' ] )
        result = wait_for_request ( pbclient , response [ 'requestId' ] )
        print ( "wait loop returned {}" . format ( str ( result ) ) )
    # end for ( disks )
    print ( "import of VM succesfully finished" )
    return 0
except KeyboardInterrupt : # handle keyboard interrupt
    return 0
except Exception :
    traceback . print_exc ( )
    sys . stderr . write ( "\n" + program_name + ":  for help use --help\n" )
    return 2


signature:
def _nsattr ( self , attr , ns = None ) :
    '''returns an attribute name w / namespace prefix'''

implementation:
if ns is None :
    return attr
return '{' + self . _ns [ ns ] + '}' + attr


signature:
def _read_config ( self , filename = None ) :
    """Read the user configuration"""

implementation:
if filename :
    self . _config_filename = filename
else :
    try :
        import appdirs
    except ImportError :
        raise Exception ( "Missing dependency for determining config path. Please install " "the 'appdirs' Python module." )
    self . _config_filename = appdirs . user_config_dir ( _LIBRARY_NAME , "ProfitBricks" ) + ".ini"
if not self . _config :
    self . _config = configparser . ConfigParser ( )
    self . _config . optionxform = str
    self . _config . read ( self . _config_filename )


signature:
def _save_config ( self , filename = None ) :
    """Save the given user configuration ."""

implementation:
if filename is None :
    filename = self . _config_filename
parent_path = os . path . dirname ( filename )
if not os . path . isdir ( parent_path ) :
    os . makedirs ( parent_path )
with open ( filename , "w" ) as configfile :
    self . _config . write ( configfile )


signature:
def _get_username ( self , username = None , use_config = True , config_filename = None ) :
    """Determine the username
 If a username is given , this name is used . Otherwise the configuration
 file will be consulted if ` use _ config ` is set to True . The user is asked
 for the username if the username is not available . Then the username is
 stored in the configuration file .
 : param username : Username ( used directly if given )
 : type username : ` ` str ` `
 : param use _ config : Whether to read username from configuration file
 : type use _ config : ` ` bool ` `
 : param config _ filename : Path to the configuration file
 : type config _ filename : ` ` str ` `"""

implementation:
if not username and use_config :
    if self . _config is None :
        self . _read_config ( config_filename )
    username = self . _config . get ( "credentials" , "username" , fallback = None )
if not username :
    username = input ( "Please enter your username: " ) . strip ( )
    while not username :
        username = input ( "No username specified. Please enter your username: " ) . strip ( )
    if 'credendials' not in self . _config :
        self . _config . add_section ( 'credentials' )
    self . _config . set ( "credentials" , "username" , username )
    self . _save_config ( )
return username


signature:
def _get_password ( self , password , use_config = True , config_filename = None , use_keyring = HAS_KEYRING ) :
    """Determine the user password
 If the password is given , this password is used . Otherwise
 this function will try to get the password from the user ' s keyring
 if ` use _ keyring ` is set to True .
 : param username : Username ( used directly if given )
 : type username : ` ` str ` `
 : param use _ config : Whether to read username from configuration file
 : type use _ config : ` ` bool ` `
 : param config _ filename : Path to the configuration file
 : type config _ filename : ` ` str ` `"""

implementation:
if not password and use_config :
    if self . _config is None :
        self . _read_config ( config_filename )
    password = self . _config . get ( "credentials" , "password" , fallback = None )
if not password and use_keyring :
    logger = logging . getLogger ( __name__ )
    question = ( "Please enter your password for {} on {}: " . format ( self . username , self . host_base ) )
    if HAS_KEYRING :
        password = keyring . get_password ( self . keyring_identificator , self . username )
        if password is None :
            password = getpass . getpass ( question )
            try :
                keyring . set_password ( self . keyring_identificator , self . username , password )
            except keyring . errors . PasswordSetError as error :
                logger . warning ( "Storing password in keyring '%s' failed: %s" , self . keyring_identificator , error )
    else :
        logger . warning ( "Install the 'keyring' Python module to store your password " "securely in your keyring!" )
        password = self . _config . get ( "credentials" , "password" , fallback = None )
        if password is None :
            password = getpass . getpass ( question )
            store_plaintext_passwords = self . _config . get ( "preferences" , "store-plaintext-passwords" , fallback = None )
            if store_plaintext_passwords != "no" :
                question = ( "Do you want to store your password in plain text in " + self . _config_filename ( ) )
                answer = ask ( question , [ "yes" , "no" , "never" ] , "no" )
                if answer == "yes" :
                    self . _config . set ( "credentials" , "password" , password )
                    self . _save_config ( )
                elif answer == "never" :
                    if "preferences" not in self . _config :
                        self . _config . add_section ( "preferences" )
                    self . _config . set ( "preferences" , "store-plaintext-passwords" , "no" )
                    self . _save_config ( )
return password


signature:
def get_datacenter ( self , datacenter_id , depth = 1 ) :
    """Retrieves a data center by its ID .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
response = self . _perform_request ( '/datacenters/%s?depth=%s' % ( datacenter_id , str ( depth ) ) )
return response


signature:
def get_datacenter_by_name ( self , name , depth = 1 ) :
    """Retrieves a data center by its name .
 Either returns the data center response or raises an Exception
 if no or more than one data center was found with the name .
 The search for the name is done in this relaxing way :
 - exact name match
 - case - insentive name match
 - data center starts with the name
 - data center starts with the name ( case insensitive )
 - name appears in the data center name
 - name appears in the data center name ( case insensitive )
 : param name : The name of the data center .
 : type name : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
all_data_centers = self . list_datacenters ( depth = depth ) [ 'items' ]
data_center = find_item_by_name ( all_data_centers , lambda i : i [ 'properties' ] [ 'name' ] , name )
if not data_center :
    raise NameError ( "No data center found with name " "containing '{name}'." . format ( name = name ) )
if len ( data_center ) > 1 :
    raise NameError ( "Found {n} data centers with the name '{name}': {names}" . format ( n = len ( data_center ) , name = name , names = ", " . join ( d [ 'properties' ] [ 'name' ] for d in data_center ) ) )
return data_center [ 0 ]


signature:
def delete_datacenter ( self , datacenter_id ) :
    """Removes the data center and all its components such as servers , NICs ,
 load balancers , volumes .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( url = '/datacenters/%s' % ( datacenter_id ) , method = 'DELETE' )
return response


signature:
def create_datacenter ( self , datacenter ) :
    """Creates a data center - - both simple and complex are supported ."""

implementation:
server_items = [ ]
volume_items = [ ]
lan_items = [ ]
loadbalancer_items = [ ]
entities = dict ( )
properties = { "name" : datacenter . name }
# Omit ' location ' , if not provided , to receive
# a meaningful error message .
if datacenter . location :
    properties [ 'location' ] = datacenter . location
# Optional Properties
if datacenter . description :
    properties [ 'description' ] = datacenter . description
# Servers
if datacenter . servers :
    for server in datacenter . servers :
        server_items . append ( self . _create_server_dict ( server ) )
    servers = { "items" : server_items }
    server_entities = { "servers" : servers }
    entities . update ( server_entities )
# Volumes
if datacenter . volumes :
    for volume in datacenter . volumes :
        volume_items . append ( self . _create_volume_dict ( volume ) )
    volumes = { "items" : volume_items }
    volume_entities = { "volumes" : volumes }
    entities . update ( volume_entities )
# Load Balancers
if datacenter . loadbalancers :
    for loadbalancer in datacenter . loadbalancers :
        loadbalancer_items . append ( self . _create_loadbalancer_dict ( loadbalancer ) )
    loadbalancers = { "items" : loadbalancer_items }
    loadbalancer_entities = { "loadbalancers" : loadbalancers }
    entities . update ( loadbalancer_entities )
# LANs
if datacenter . lans :
    for lan in datacenter . lans :
        lan_items . append ( self . _create_lan_dict ( lan ) )
    lans = { "items" : lan_items }
    lan_entities = { "lans" : lans }
    entities . update ( lan_entities )
if not entities :
    raw = { "properties" : properties , }
else :
    raw = { "properties" : properties , "entities" : entities }
data = json . dumps ( raw )
response = self . _perform_request ( url = '/datacenters' , method = 'POST' , data = data )
return response


signature:
def get_firewall_rule ( self , datacenter_id , server_id , nic_id , firewall_rule_id ) :
    """Retrieves a single firewall rule by ID .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `
 : param nic _ id : The unique ID of the NIC .
 : type nic _ id : ` ` str ` `
 : param firewall _ rule _ id : The unique ID of the firewall rule .
 : type firewall _ rule _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( '/datacenters/%s/servers/%s/nics/%s/firewallrules/%s' % ( datacenter_id , server_id , nic_id , firewall_rule_id ) )
return response


signature:
def delete_firewall_rule ( self , datacenter_id , server_id , nic_id , firewall_rule_id ) :
    """Removes a firewall rule from the NIC .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `
 : param nic _ id : The unique ID of the NIC .
 : type nic _ id : ` ` str ` `
 : param firewall _ rule _ id : The unique ID of the firewall rule .
 : type firewall _ rule _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( url = '/datacenters/%s/servers/%s/nics/%s/firewallrules/%s' % ( datacenter_id , server_id , nic_id , firewall_rule_id ) , method = 'DELETE' )
return response


signature:
def create_firewall_rule ( self , datacenter_id , server_id , nic_id , firewall_rule ) :
    """Creates a firewall rule on the specified NIC and server .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `
 : param nic _ id : The unique ID of the NIC .
 : type nic _ id : ` ` str ` `
 : param firewall _ rule : A firewall rule dict .
 : type firewall _ rule : ` ` dict ` `"""

implementation:
properties = { "name" : firewall_rule . name }
if firewall_rule . protocol :
    properties [ 'protocol' ] = firewall_rule . protocol
# Optional Properties
if firewall_rule . source_mac :
    properties [ 'sourceMac' ] = firewall_rule . source_mac
if firewall_rule . source_ip :
    properties [ 'sourceIp' ] = firewall_rule . source_ip
if firewall_rule . target_ip :
    properties [ 'targetIp' ] = firewall_rule . target_ip
if firewall_rule . port_range_start :
    properties [ 'portRangeStart' ] = firewall_rule . port_range_start
if firewall_rule . port_range_end :
    properties [ 'portRangeEnd' ] = firewall_rule . port_range_end
if firewall_rule . icmp_type :
    properties [ 'icmpType' ] = firewall_rule . icmp_type
if firewall_rule . icmp_code :
    properties [ 'icmpCode' ] = firewall_rule . icmp_code
data = { "properties" : properties }
response = self . _perform_request ( url = '/datacenters/%s/servers/%s/nics/%s/firewallrules' % ( datacenter_id , server_id , nic_id ) , method = 'POST' , data = json . dumps ( data ) )
return response


signature:
def update_firewall_rule ( self , datacenter_id , server_id , nic_id , firewall_rule_id , ** kwargs ) :
    """Updates a firewall rule .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `
 : param nic _ id : The unique ID of the NIC .
 : type nic _ id : ` ` str ` `
 : param firewall _ rule _ id : The unique ID of the firewall rule .
 : type firewall _ rule _ id : ` ` str ` `"""

implementation:
data = { }
for attr , value in kwargs . items ( ) :
    data [ self . _underscore_to_camelcase ( attr ) ] = value
    if attr == 'source_mac' :
        data [ 'sourceMac' ] = value
    elif attr == 'source_ip' :
        data [ 'sourceIp' ] = value
    elif attr == 'target_ip' :
        data [ 'targetIp' ] = value
    elif attr == 'port_range_start' :
        data [ 'portRangeStart' ] = value
    elif attr == 'port_range_end' :
        data [ 'portRangeEnd' ] = value
    elif attr == 'icmp_type' :
        data [ 'icmpType' ] = value
    elif attr == 'icmp_code' :
        data [ 'icmpCode' ] = value
    else :
        data [ self . _underscore_to_camelcase ( attr ) ] = value
response = self . _perform_request ( url = '/datacenters/%s/servers/%s/nics/%s/firewallrules/%s' % ( datacenter_id , server_id , nic_id , firewall_rule_id ) , method = 'PATCH' , data = json . dumps ( data ) )
return response


signature:
def delete_image ( self , image_id ) :
    """Removes only user created images .
 : param image _ id : The unique ID of the image .
 : type image _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( url = '/images/' + image_id , method = 'DELETE' )
return response


signature:
def update_image ( self , image_id , ** kwargs ) :
    """Replace all properties of an image ."""

implementation:
data = { }
for attr , value in kwargs . items ( ) :
    data [ self . _underscore_to_camelcase ( attr ) ] = value
response = self . _perform_request ( url = '/images/' + image_id , method = 'PATCH' , data = json . dumps ( data ) )
return response


signature:
def delete_ipblock ( self , ipblock_id ) :
    """Removes a single IP block from your account .
 : param ipblock _ id : The unique ID of the IP block .
 : type ipblock _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( url = '/ipblocks/' + ipblock_id , method = 'DELETE' )
return response


signature:
def reserve_ipblock ( self , ipblock ) :
    """Reserves an IP block within your account ."""

implementation:
properties = { "name" : ipblock . name }
if ipblock . location :
    properties [ 'location' ] = ipblock . location
if ipblock . size :
    properties [ 'size' ] = str ( ipblock . size )
raw = { "properties" : properties , }
response = self . _perform_request ( url = '/ipblocks' , method = 'POST' , data = json . dumps ( raw ) )
return response


signature:
def get_lan ( self , datacenter_id , lan_id , depth = 1 ) :
    """Retrieves a single LAN by ID .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param lan _ id : The unique ID of the LAN .
 : type lan _ id : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
response = self . _perform_request ( '/datacenters/%s/lans/%s?depth=%s' % ( datacenter_id , lan_id , str ( depth ) ) )
return response


signature:
def list_lans ( self , datacenter_id , depth = 1 ) :
    """Retrieves a list of LANs available in the account .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
response = self . _perform_request ( '/datacenters/%s/lans?depth=%s' % ( datacenter_id , str ( depth ) ) )
return response


signature:
def delete_lan ( self , datacenter_id , lan_id ) :
    """Removes a LAN from the data center .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param lan _ id : The unique ID of the LAN .
 : type lan _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( url = '/datacenters/%s/lans/%s' % ( datacenter_id , lan_id ) , method = 'DELETE' )
return response


signature:
def create_lan ( self , datacenter_id , lan ) :
    """Creates a LAN in the data center .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param lan : The LAN object to be created .
 : type lan : ` ` dict ` `"""

implementation:
data = json . dumps ( self . _create_lan_dict ( lan ) )
response = self . _perform_request ( url = '/datacenters/%s/lans' % datacenter_id , method = 'POST' , data = data )
return response


signature:
def update_lan ( self , datacenter_id , lan_id , name = None , public = None , ip_failover = None ) :
    """Updates a LAN
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param lan _ id : The unique ID of the LAN .
 : type lan _ id : ` ` str ` `
 : param name : The new name of the LAN .
 : type name : ` ` str ` `
 : param public : Indicates if the LAN is public .
 : type public : ` ` bool ` `
 : param ip _ failover : A list of IP fail - over dicts .
 : type ip _ failover : ` ` list ` `"""

implementation:
data = { }
if name :
    data [ 'name' ] = name
if public is not None :
    data [ 'public' ] = public
if ip_failover :
    data [ 'ipFailover' ] = ip_failover
response = self . _perform_request ( url = '/datacenters/%s/lans/%s' % ( datacenter_id , lan_id ) , method = 'PATCH' , data = json . dumps ( data ) )
return response


signature:
def get_lan_members ( self , datacenter_id , lan_id , depth = 1 ) :
    """Retrieves the list of NICs that are part of the LAN .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param lan _ id : The unique ID of the LAN .
 : type lan _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( '/datacenters/%s/lans/%s/nics?depth=%s' % ( datacenter_id , lan_id , str ( depth ) ) )
return response


signature:
def get_loadbalancer ( self , datacenter_id , loadbalancer_id ) :
    """Retrieves a single load balancer by ID .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param loadbalancer _ id : The unique ID of the load balancer .
 : type loadbalancer _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( '/datacenters/%s/loadbalancers/%s' % ( datacenter_id , loadbalancer_id ) )
return response


signature:
def list_loadbalancers ( self , datacenter_id , depth = 1 ) :
    """Retrieves a list of load balancers in the data center .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
response = self . _perform_request ( '/datacenters/%s/loadbalancers?depth=%s' % ( datacenter_id , str ( depth ) ) )
return response


signature:
def delete_loadbalancer ( self , datacenter_id , loadbalancer_id ) :
    """Removes the load balancer from the data center .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param loadbalancer _ id : The unique ID of the load balancer .
 : type loadbalancer _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( url = '/datacenters/%s/loadbalancers/%s' % ( datacenter_id , loadbalancer_id ) , method = 'DELETE' )
return response


signature:
def create_loadbalancer ( self , datacenter_id , loadbalancer ) :
    """Creates a load balancer within the specified data center .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param loadbalancer : The load balancer object to be created .
 : type loadbalancer : ` ` dict ` `"""

implementation:
data = json . dumps ( self . _create_loadbalancer_dict ( loadbalancer ) )
response = self . _perform_request ( url = '/datacenters/%s/loadbalancers' % datacenter_id , method = 'POST' , data = data )
return response


signature:
def update_loadbalancer ( self , datacenter_id , loadbalancer_id , ** kwargs ) :
    """Updates a load balancer
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param loadbalancer _ id : The unique ID of the load balancer .
 : type loadbalancer _ id : ` ` str ` `"""

implementation:
data = { }
for attr , value in kwargs . items ( ) :
    data [ self . _underscore_to_camelcase ( attr ) ] = value
response = self . _perform_request ( url = '/datacenters/%s/loadbalancers/%s' % ( datacenter_id , loadbalancer_id ) , method = 'PATCH' , data = json . dumps ( data ) )
return response


signature:
def get_loadbalancer_members ( self , datacenter_id , loadbalancer_id , depth = 1 ) :
    """Retrieves the list of NICs that are associated with a load balancer .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param loadbalancer _ id : The unique ID of the load balancer .
 : type loadbalancer _ id : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
response = self . _perform_request ( '/datacenters/%s/loadbalancers/%s/balancednics?depth=%s' % ( datacenter_id , loadbalancer_id , str ( depth ) ) )
return response


signature:
def add_loadbalanced_nics ( self , datacenter_id , loadbalancer_id , nic_id ) :
    """Associates a NIC with the given load balancer .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param loadbalancer _ id : The unique ID of the load balancer .
 : type loadbalancer _ id : ` ` str ` `
 : param nic _ id : The ID of the NIC .
 : type nic _ id : ` ` str ` `"""

implementation:
data = '{ "id": "' + nic_id + '" }'
response = self . _perform_request ( url = '/datacenters/%s/loadbalancers/%s/balancednics' % ( datacenter_id , loadbalancer_id ) , method = 'POST' , data = data )
return response


signature:
def get_loadbalanced_nic ( self , datacenter_id , loadbalancer_id , nic_id , depth = 1 ) :
    """Gets the properties of a load balanced NIC .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param loadbalancer _ id : The unique ID of the load balancer .
 : type loadbalancer _ id : ` ` str ` `
 : param nic _ id : The unique ID of the NIC .
 : type nic _ id : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
response = self . _perform_request ( '/datacenters/%s/loadbalancers/%s/balancednics/%s?depth=%s' % ( datacenter_id , loadbalancer_id , nic_id , str ( depth ) ) )
return response


signature:
def remove_loadbalanced_nic ( self , datacenter_id , loadbalancer_id , nic_id ) :
    """Removes a NIC from the load balancer .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param loadbalancer _ id : The unique ID of the load balancer .
 : type loadbalancer _ id : ` ` str ` `
 : param nic _ id : The unique ID of the NIC .
 : type nic _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( url = '/datacenters/%s/loadbalancers/%s/balancednics/%s' % ( datacenter_id , loadbalancer_id , nic_id ) , method = 'DELETE' )
return response


signature:
def get_location ( self , location_id , depth = 0 ) :
    """Retrieves a single location by ID .
 : param location _ id : The unique ID of the location .
 : type location _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( '/locations/%s?depth=%s' % ( location_id , depth ) )
return response


signature:
def get_nic ( self , datacenter_id , server_id , nic_id , depth = 1 ) :
    """Retrieves a NIC by its ID .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `
 : param nic _ id : The unique ID of the NIC .
 : type nic _ id : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
response = self . _perform_request ( '/datacenters/%s/servers/%s/nics/%s?depth=%s' % ( datacenter_id , server_id , nic_id , str ( depth ) ) )
return response


signature:
def list_nics ( self , datacenter_id , server_id , depth = 1 ) :
    """Retrieves a list of all NICs bound to the specified server .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
response = self . _perform_request ( '/datacenters/%s/servers/%s/nics?depth=%s' % ( datacenter_id , server_id , str ( depth ) ) )
return response


signature:
def delete_nic ( self , datacenter_id , server_id , nic_id ) :
    """Removes a NIC from the server .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `
 : param nic _ id : The unique ID of the NIC .
 : type nic _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( url = '/datacenters/%s/servers/%s/nics/%s' % ( datacenter_id , server_id , nic_id ) , method = 'DELETE' )
return response


signature:
def create_nic ( self , datacenter_id , server_id , nic ) :
    """Creates a NIC on the specified server .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `
 : param nic : A NIC dict .
 : type nic : ` ` dict ` `"""

implementation:
data = json . dumps ( self . _create_nic_dict ( nic ) )
response = self . _perform_request ( url = '/datacenters/%s/servers/%s/nics' % ( datacenter_id , server_id ) , method = 'POST' , data = data )
return response


signature:
def update_nic ( self , datacenter_id , server_id , nic_id , ** kwargs ) :
    """Updates a NIC with the parameters provided .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `
 : param nic _ id : The unique ID of the NIC .
 : type nic _ id : ` ` str ` `"""

implementation:
data = { }
for attr , value in kwargs . items ( ) :
    data [ self . _underscore_to_camelcase ( attr ) ] = value
response = self . _perform_request ( url = '/datacenters/%s/servers/%s/nics/%s' % ( datacenter_id , server_id , nic_id ) , method = 'PATCH' , data = json . dumps ( data ) )
return response


signature:
def get_request ( self , request_id , status = False ) :
    """Retrieves a single request by ID .
 : param request _ id : The unique ID of the request .
 : type request _ id : ` ` str ` `
 : param status : Retreive the full status of the request .
 : type status : ` ` bool ` `"""

implementation:
if status :
    response = self . _perform_request ( '/requests/' + request_id + '/status' )
else :
    response = self . _perform_request ( '/requests/%s' % request_id )
return response


signature:
def get_server ( self , datacenter_id , server_id , depth = 1 ) :
    """Retrieves a server by its ID .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
response = self . _perform_request ( '/datacenters/%s/servers/%s?depth=%s' % ( datacenter_id , server_id , str ( depth ) ) )
return response


signature:
def list_servers ( self , datacenter_id , depth = 1 ) :
    """Retrieves a list of all servers bound to the specified data center .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
response = self . _perform_request ( '/datacenters/%s/servers?depth=%s' % ( datacenter_id , str ( depth ) ) )
return response


signature:
def delete_server ( self , datacenter_id , server_id ) :
    """Removes the server from your data center .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( url = '/datacenters/%s/servers/%s' % ( datacenter_id , server_id ) , method = 'DELETE' )
return response


signature:
def create_server ( self , datacenter_id , server ) :
    """Creates a server within the data center .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server : A dict of the server to be created .
 : type server : ` ` dict ` `"""

implementation:
data = json . dumps ( self . _create_server_dict ( server ) )
response = self . _perform_request ( url = '/datacenters/%s/servers' % ( datacenter_id ) , method = 'POST' , data = data )
return response


signature:
def update_server ( self , datacenter_id , server_id , ** kwargs ) :
    """Updates a server with the parameters provided .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `"""

implementation:
data = { }
for attr , value in kwargs . items ( ) :
    if attr == 'boot_volume' :
        boot_volume_properties = { "id" : value }
        boot_volume_entities = { "bootVolume" : boot_volume_properties }
        data . update ( boot_volume_entities )
    else :
        data [ self . _underscore_to_camelcase ( attr ) ] = value
response = self . _perform_request ( url = '/datacenters/%s/servers/%s' % ( datacenter_id , server_id ) , method = 'PATCH' , data = json . dumps ( data ) )
return response


signature:
def get_attached_volumes ( self , datacenter_id , server_id , depth = 1 ) :
    """Retrieves a list of volumes attached to the server .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
response = self . _perform_request ( '/datacenters/%s/servers/%s/volumes?depth=%s' % ( datacenter_id , server_id , str ( depth ) ) )
return response


signature:
def get_attached_volume ( self , datacenter_id , server_id , volume_id ) :
    """Retrieves volume information .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `
 : param volume _ id : The unique ID of the volume .
 : type volume _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( '/datacenters/%s/servers/%s/volumes/%s' % ( datacenter_id , server_id , volume_id ) )
return response


signature:
def attach_volume ( self , datacenter_id , server_id , volume_id ) :
    """Attaches a volume to a server .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `
 : param volume _ id : The unique ID of the volume .
 : type volume _ id : ` ` str ` `"""

implementation:
data = '{ "id": "' + volume_id + '" }'
response = self . _perform_request ( url = '/datacenters/%s/servers/%s/volumes' % ( datacenter_id , server_id ) , method = 'POST' , data = data )
return response


signature:
def detach_volume ( self , datacenter_id , server_id , volume_id ) :
    """Detaches a volume from a server .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `
 : param volume _ id : The unique ID of the volume .
 : type volume _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( url = '/datacenters/%s/servers/%s/volumes/%s' % ( datacenter_id , server_id , volume_id ) , method = 'DELETE' )
return response


signature:
def get_attached_cdroms ( self , datacenter_id , server_id , depth = 1 ) :
    """Retrieves a list of CDROMs attached to the server .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
response = self . _perform_request ( '/datacenters/%s/servers/%s/cdroms?depth=%s' % ( datacenter_id , server_id , str ( depth ) ) )
return response


signature:
def get_attached_cdrom ( self , datacenter_id , server_id , cdrom_id ) :
    """Retrieves an attached CDROM .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `
 : param cdrom _ id : The unique ID of the CDROM .
 : type cdrom _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( '/datacenters/%s/servers/%s/cdroms/%s' % ( datacenter_id , server_id , cdrom_id ) )
return response


signature:
def attach_cdrom ( self , datacenter_id , server_id , cdrom_id ) :
    """Attaches a CDROM to a server .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `
 : param cdrom _ id : The unique ID of the CDROM .
 : type cdrom _ id : ` ` str ` `"""

implementation:
data = '{ "id": "' + cdrom_id + '" }'
response = self . _perform_request ( url = '/datacenters/%s/servers/%s/cdroms' % ( datacenter_id , server_id ) , method = 'POST' , data = data )
return response


signature:
def detach_cdrom ( self , datacenter_id , server_id , cdrom_id ) :
    """Detaches a volume from a server .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `
 : param cdrom _ id : The unique ID of the CDROM .
 : type cdrom _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( url = '/datacenters/%s/servers/%s/cdroms/%s' % ( datacenter_id , server_id , cdrom_id ) , method = 'DELETE' )
return response


signature:
def start_server ( self , datacenter_id , server_id ) :
    """Starts the server .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( url = '/datacenters/%s/servers/%s/start' % ( datacenter_id , server_id ) , method = 'POST-ACTION' )
return response


signature:
def stop_server ( self , datacenter_id , server_id ) :
    """Stops the server .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( url = '/datacenters/%s/servers/%s/stop' % ( datacenter_id , server_id ) , method = 'POST-ACTION' )
return response


signature:
def reboot_server ( self , datacenter_id , server_id ) :
    """Reboots the server .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param server _ id : The unique ID of the server .
 : type server _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( url = '/datacenters/%s/servers/%s/reboot' % ( datacenter_id , server_id ) , method = 'POST-ACTION' )
return response


signature:
def delete_snapshot ( self , snapshot_id ) :
    """Removes a snapshot from your account .
 : param snapshot _ id : The unique ID of the snapshot .
 : type snapshot _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( url = '/snapshots/' + snapshot_id , method = 'DELETE' )
return response


signature:
def update_snapshot ( self , snapshot_id , ** kwargs ) :
    """Removes a snapshot from your account .
 : param snapshot _ id : The unique ID of the snapshot .
 : type snapshot _ id : ` ` str ` `"""

implementation:
data = { }
for attr , value in kwargs . items ( ) :
    data [ self . _underscore_to_camelcase ( attr ) ] = value
response = self . _perform_request ( url = '/snapshots/' + snapshot_id , method = 'PATCH' , data = json . dumps ( data ) )
return response


signature:
def create_snapshot ( self , datacenter_id , volume_id , name = None , description = None ) :
    """Creates a snapshot of the specified volume .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param volume _ id : The unique ID of the volume .
 : type volume _ id : ` ` str ` `
 : param name : The name given to the volume .
 : type name : ` ` str ` `
 : param description : The description given to the volume .
 : type description : ` ` str ` `"""

implementation:
data = { 'name' : name , 'description' : description }
response = self . _perform_request ( '/datacenters/%s/volumes/%s/create-snapshot' % ( datacenter_id , volume_id ) , method = 'POST-ACTION-JSON' , data = urlencode ( data ) )
return response


signature:
def restore_snapshot ( self , datacenter_id , volume_id , snapshot_id ) :
    """Restores a snapshot to the specified volume .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param volume _ id : The unique ID of the volume .
 : type volume _ id : ` ` str ` `
 : param snapshot _ id : The unique ID of the snapshot .
 : type snapshot _ id : ` ` str ` `"""

implementation:
data = { 'snapshotId' : snapshot_id }
response = self . _perform_request ( url = '/datacenters/%s/volumes/%s/restore-snapshot' % ( datacenter_id , volume_id ) , method = 'POST-ACTION' , data = urlencode ( data ) )
return response


signature:
def remove_snapshot ( self , snapshot_id ) :
    """Removes a snapshot .
 : param snapshot _ id : The ID of the snapshot
 you wish to remove .
 : type snapshot _ id : ` ` str ` `"""


signature:
def get_group ( self , group_id , depth = 1 ) :
    """Retrieves a single group by ID .
 : param group _ id : The unique ID of the group .
 : type group _ id : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
response = self . _perform_request ( '/um/groups/%s?depth=%s' % ( group_id , str ( depth ) ) )
return response


signature:
def create_group ( self , group ) :
    """Creates a new group and set group privileges .
 : param group : The group object to be created .
 : type group : ` ` dict ` `"""

implementation:
data = json . dumps ( self . _create_group_dict ( group ) )
response = self . _perform_request ( url = '/um/groups' , method = 'POST' , data = data )
return response


signature:
def update_group ( self , group_id , ** kwargs ) :
    """Updates a group .
 : param group _ id : The unique ID of the group .
 : type group _ id : ` ` str ` `"""

implementation:
properties = { }
# make the key camel - case transformable
if 'create_datacenter' in kwargs :
    kwargs [ 'create_data_center' ] = kwargs . pop ( 'create_datacenter' )
for attr , value in kwargs . items ( ) :
    properties [ self . _underscore_to_camelcase ( attr ) ] = value
data = { "properties" : properties }
response = self . _perform_request ( url = '/um/groups/%s' % group_id , method = 'PUT' , data = json . dumps ( data ) )
return response


signature:
def delete_group ( self , group_id ) :
    """Removes a group .
 : param group _ id : The unique ID of the group .
 : type group _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( url = '/um/groups/%s' % group_id , method = 'DELETE' )
return response


signature:
def list_shares ( self , group_id , depth = 1 ) :
    """Retrieves a list of all shares though a group .
 : param group _ id : The unique ID of the group .
 : type group _ id : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
response = self . _perform_request ( '/um/groups/%s/shares?depth=%s' % ( group_id , str ( depth ) ) )
return response


signature:
def get_share ( self , group_id , resource_id , depth = 1 ) :
    """Retrieves a specific resource share available to a group .
 : param group _ id : The unique ID of the group .
 : type group _ id : ` ` str ` `
 : param resource _ id : The unique ID of the resource .
 : type resource _ id : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
response = self . _perform_request ( '/um/groups/%s/shares/%s?depth=%s' % ( group_id , resource_id , str ( depth ) ) )
return response


signature:
def add_share ( self , group_id , resource_id , ** kwargs ) :
    """Shares a resource through a group .
 : param group _ id : The unique ID of the group .
 : type group _ id : ` ` str ` `
 : param resource _ id : The unique ID of the resource .
 : type resource _ id : ` ` str ` `"""

implementation:
properties = { }
for attr , value in kwargs . items ( ) :
    properties [ self . _underscore_to_camelcase ( attr ) ] = value
data = { "properties" : properties }
response = self . _perform_request ( url = '/um/groups/%s/shares/%s' % ( group_id , resource_id ) , method = 'POST' , data = json . dumps ( data ) )
return response


signature:
def delete_share ( self , group_id , resource_id ) :
    """Removes a resource share from a group .
 : param group _ id : The unique ID of the group .
 : type group _ id : ` ` str ` `
 : param resource _ id : The unique ID of the resource .
 : type resource _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( url = '/um/groups/%s/shares/%s' % ( group_id , resource_id ) , method = 'DELETE' )
return response


signature:
def get_user ( self , user_id , depth = 1 ) :
    """Retrieves a single user by ID .
 : param user _ id : The unique ID of the user .
 : type user _ id : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
response = self . _perform_request ( '/um/users/%s?depth=%s' % ( user_id , str ( depth ) ) )
return response


signature:
def create_user ( self , user ) :
    """Creates a new user .
 : param user : The user object to be created .
 : type user : ` ` dict ` `"""

implementation:
data = self . _create_user_dict ( user = user )
response = self . _perform_request ( url = '/um/users' , method = 'POST' , data = json . dumps ( data ) )
return response


signature:
def update_user ( self , user_id , ** kwargs ) :
    """Updates a user .
 : param user _ id : The unique ID of the user .
 : type user _ id : ` ` str ` `"""

implementation:
properties = { }
for attr , value in kwargs . items ( ) :
    properties [ self . _underscore_to_camelcase ( attr ) ] = value
data = { "properties" : properties }
response = self . _perform_request ( url = '/um/users/%s' % user_id , method = 'PUT' , data = json . dumps ( data ) )
return response


signature:
def delete_user ( self , user_id ) :
    """Removes a user .
 : param user _ id : The unique ID of the user .
 : type user _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( url = '/um/users/%s' % user_id , method = 'DELETE' )
return response


signature:
def list_group_users ( self , group_id , depth = 1 ) :
    """Retrieves a list of all users that are members of a particular group .
 : param group _ id : The unique ID of the group .
 : type group _ id : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
response = self . _perform_request ( '/um/groups/%s/users?depth=%s' % ( group_id , str ( depth ) ) )
return response


signature:
def add_group_user ( self , group_id , user_id ) :
    """Adds an existing user to a group .
 : param group _ id : The unique ID of the group .
 : type group _ id : ` ` str ` `
 : param user _ id : The unique ID of the user .
 : type user _ id : ` ` str ` `"""

implementation:
data = { "id" : user_id }
response = self . _perform_request ( url = '/um/groups/%s/users' % group_id , method = 'POST' , data = json . dumps ( data ) )
return response


signature:
def remove_group_user ( self , group_id , user_id ) :
    """Removes a user from a group .
 : param group _ id : The unique ID of the group .
 : type group _ id : ` ` str ` `
 : param user _ id : The unique ID of the user .
 : type user _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( url = '/um/groups/%s/users/%s' % ( group_id , user_id ) , method = 'DELETE' )
return response


signature:
def list_resources ( self , resource_type = None , depth = 1 ) :
    """Retrieves a list of all resources .
 : param resource _ type : The resource type : datacenter , image ,
 snapshot or ipblock . Default is None ,
 i . e . , all resources are listed .
 : type resource _ type : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
if resource_type is not None :
    response = self . _perform_request ( '/um/resources/%s?depth=%s' % ( resource_type , str ( depth ) ) )
else :
    response = self . _perform_request ( '/um/resources?depth=' + str ( depth ) )
return response


signature:
def get_resource ( self , resource_type , resource_id , depth = 1 ) :
    """Retrieves a single resource of a particular type .
 : param resource _ type : The resource type : datacenter , image ,
 snapshot or ipblock .
 : type resource _ type : ` ` str ` `
 : param resource _ id : The unique ID of the resource .
 : type resource _ id : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
response = self . _perform_request ( '/um/resources/%s/%s?depth=%s' % ( resource_type , resource_id , str ( depth ) ) )
return response


signature:
def get_volume ( self , datacenter_id , volume_id ) :
    """Retrieves a single volume by ID .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param volume _ id : The unique ID of the volume .
 : type volume _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( '/datacenters/%s/volumes/%s' % ( datacenter_id , volume_id ) )
return response


signature:
def list_volumes ( self , datacenter_id , depth = 1 ) :
    """Retrieves a list of volumes in the data center .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param depth : The depth of the response data .
 : type depth : ` ` int ` `"""

implementation:
response = self . _perform_request ( '/datacenters/%s/volumes?depth=%s' % ( datacenter_id , str ( depth ) ) )
return response


signature:
def delete_volume ( self , datacenter_id , volume_id ) :
    """Removes a volume from the data center .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param volume _ id : The unique ID of the volume .
 : type volume _ id : ` ` str ` `"""

implementation:
response = self . _perform_request ( url = '/datacenters/%s/volumes/%s' % ( datacenter_id , volume_id ) , method = 'DELETE' )
return response


signature:
def create_volume ( self , datacenter_id , volume ) :
    """Creates a volume within the specified data center .
 : param datacenter _ id : The unique ID of the data center .
 : type datacenter _ id : ` ` str ` `
 : param volume : A volume dict .
 : type volume : ` ` dict ` `"""

implementation:
data = ( json . dumps ( self . _create_volume_dict ( volume ) ) )
response = self . _perform_request ( url = '/datacenters/%s/volumes' % datacenter_id , method = 'POST' , data = data )
return response


signature:
def wait_for_completion ( self , response , timeout = 3600 , initial_wait = 5 , scaleup = 10 ) :
    """Poll resource request status until resource is provisioned .
 : param response : A response dict , which needs to have a ' requestId ' item .
 : type response : ` ` dict ` `
 : param timeout : Maximum waiting time in seconds . None means infinite waiting time .
 : type timeout : ` ` int ` `
 : param initial _ wait : Initial polling interval in seconds .
 : type initial _ wait : ` ` int ` `
 : param scaleup : Double polling interval every scaleup steps , which will be doubled .
 : type scaleup : ` ` int ` `"""

implementation:
if not response :
    return
logger = logging . getLogger ( __name__ )
wait_period = initial_wait
next_increase = time . time ( ) + wait_period * scaleup
if timeout :
    timeout = time . time ( ) + timeout
while True :
    request = self . get_request ( request_id = response [ 'requestId' ] , status = True )
    if request [ 'metadata' ] [ 'status' ] == 'DONE' :
        break
    elif request [ 'metadata' ] [ 'status' ] == 'FAILED' :
        raise PBFailedRequest ( 'Request {0} failed to complete: {1}' . format ( response [ 'requestId' ] , request [ 'metadata' ] [ 'message' ] ) , response [ 'requestId' ] )
    current_time = time . time ( )
    if timeout and current_time > timeout :
        raise PBTimeoutError ( 'Timed out waiting for request {0}.' . format ( response [ 'requestId' ] ) , response [ 'requestId' ] )
    if current_time > next_increase :
        wait_period *= 2
        next_increase = time . time ( ) + wait_period * scaleup
        scaleup *= 2
    logger . info ( "Request %s is in state '%s'. Sleeping for %i seconds..." , response [ 'requestId' ] , request [ 'metadata' ] [ 'status' ] , wait_period )
    time . sleep ( wait_period )


signature:
def _b ( s , encoding = 'utf-8' ) :
    """Returns the given string as a string of bytes . That means in
 Python2 as a str object , and in Python3 as a bytes object .
 Raises a TypeError , if it cannot be converted ."""

implementation:
if six . PY2 : # This is Python2
    if isinstance ( s , str ) :
        return s
    elif isinstance ( s , unicode ) : # noqa , pylint : disable = undefined - variable
        return s . encode ( encoding )
else : # And this is Python3
    if isinstance ( s , bytes ) :
        return s
    elif isinstance ( s , str ) :
        return s . encode ( encoding )
raise TypeError ( "Invalid argument %r for _b()" % ( s , ) )


signature:
def _underscore_to_camelcase ( value ) :
    """Convert Python snake case back to mixed case ."""

implementation:
def camelcase ( ) :
    yield str . lower
    while True :
        yield str . capitalize
c = camelcase ( )
return "" . join ( next ( c ) ( x ) if x else '_' for x in value . split ( "_" ) )


signature:
def ask ( question , options , default ) :
    """Ask the user a question with a list of allowed answers ( like yes or no ) .
 The user is presented with a question and asked to select an answer from
 the given options list . The default will be returned if the user enters
 nothing . The user is asked to repeat his answer if his answer does not
 match any of the allowed anwsers .
 : param question : Question to present to the user ( without question mark )
 : type question : ` ` str ` `
 : param options : List of allowed anwsers
 : type options : ` ` list ` `
 : param default : Default answer ( if the user enters no text )
 : type default : ` ` str ` `"""

implementation:
assert default in options
question += " ({})? " . format ( "/" . join ( o . upper ( ) if o == default else o for o in options ) )
selected = None
while selected not in options :
    selected = input ( question ) . strip ( ) . lower ( )
    if selected == "" :
        selected = default
    else :
        if selected not in options :
            question = "Please type '{}'{comma} or '{}': " . format ( "', '" . join ( options [ : - 1 ] ) , options [ - 1 ] , comma = ',' if len ( options ) > 2 else '' , )
return selected


signature:
def find_item_by_name ( list_ , namegetter , name ) :
    """Find a item a given list by a matching name .
 The search for the name is done in this relaxing way :
 - exact name match
 - case - insentive name match
 - attribute starts with the name
 - attribute starts with the name ( case insensitive )
 - name appears in the attribute
 - name appears in the attribute ( case insensitive )
 : param list _ : A list of elements
 : type list _ : ` ` list ` `
 : param namegetter : Function that returns the name for a given
 element in the list
 : type namegetter : ` ` function ` `
 : param name : Name to search for
 : type name : ` ` str ` `"""

implementation:
matching_items = [ i for i in list_ if namegetter ( i ) == name ]
if not matching_items :
    prog = re . compile ( re . escape ( name ) + '$' , re . IGNORECASE )
    matching_items = [ i for i in list_ if prog . match ( namegetter ( i ) ) ]
if not matching_items :
    prog = re . compile ( re . escape ( name ) )
    matching_items = [ i for i in list_ if prog . match ( namegetter ( i ) ) ]
if not matching_items :
    prog = re . compile ( re . escape ( name ) , re . IGNORECASE )
    matching_items = [ i for i in list_ if prog . match ( namegetter ( i ) ) ]
if not matching_items :
    prog = re . compile ( re . escape ( name ) )
    matching_items = [ i for i in list_ if prog . search ( namegetter ( i ) ) ]
if not matching_items :
    prog = re . compile ( re . escape ( name ) , re . IGNORECASE )
    matching_items = [ i for i in list_ if prog . search ( namegetter ( i ) ) ]
return matching_items


signature:
def create_datacenter_dict ( pbclient , datacenter ) :
    """Creates a Datacenter dict - - both simple and complex are supported .
 This is copied from createDatacenter ( ) and uses private methods ."""

implementation:
# pylint : disable = protected - access
server_items = [ ]
volume_items = [ ]
lan_items = [ ]
loadbalancer_items = [ ]
entities = dict ( )
properties = { "name" : datacenter . name , "location" : datacenter . location , }
# Optional Properties
if datacenter . description :
    properties [ 'description' ] = datacenter . description
# Servers
if datacenter . servers :
    for server in datacenter . servers :
        server_items . append ( pbclient . _create_server_dict ( server ) )
    servers = { "items" : server_items }
    server_entities = { "servers" : servers }
    entities . update ( server_entities )
# Volumes
if datacenter . volumes :
    for volume in datacenter . volumes :
        volume_items . append ( pbclient . _create_volume_dict ( volume ) )
    volumes = { "items" : volume_items }
    volume_entities = { "volumes" : volumes }
    entities . update ( volume_entities )
# Load Balancers
if datacenter . loadbalancers :
    for loadbalancer in datacenter . loadbalancers :
        loadbalancer_items . append ( pbclient . _create_loadbalancer_dict ( loadbalancer ) )
    loadbalancers = { "items" : loadbalancer_items }
    loadbalancer_entities = { "loadbalancers" : loadbalancers }
    entities . update ( loadbalancer_entities )
# LANs
if datacenter . lans :
    for lan in datacenter . lans :
        lan_items . append ( pbclient . _create_lan_dict ( lan ) )
    lans = { "items" : lan_items }
    lan_entities = { "lans" : lans }
    entities . update ( lan_entities )
if not entities :
    raw = { "properties" : properties , }
else :
    raw = { "properties" : properties , "entities" : entities }
return raw


signature:
def main ( argv = None ) :
    '''Parse command line options and create a server / volume composite .'''

implementation:
if argv is None :
    argv = sys . argv
else :
    sys . argv . extend ( argv )
program_name = os . path . basename ( sys . argv [ 0 ] )
program_version = "v%s" % __version__
program_build_date = str ( __updated__ )
program_version_message = '%%(prog)s %s (%s)' % ( program_version , program_build_date )
program_shortdesc = __import__ ( '__main__' ) . __doc__ . split ( "\n" ) [ 1 ]
program_license = '''%s

  Created by J. Buchhammer on %s.
  Copyright 2016 ProfitBricks GmbH. All rights reserved.

  Licensed under the Apache License 2.0
  http://www.apache.org/licenses/LICENSE-2.0

  Distributed on an "AS IS" basis without warranties
  or conditions of any kind, either express or implied.

USAGE
''' % ( program_shortdesc , str ( __date__ ) )
# Setup argument parser
parser = ArgumentParser ( description = program_license , formatter_class = RawDescriptionHelpFormatter )
parser . add_argument ( '-u' , '--user' , dest = 'user' , help = 'the login name' )
parser . add_argument ( '-p' , '--password' , dest = 'password' , help = 'the login password' )
parser . add_argument ( '-L' , '--Login' , dest = 'loginfile' , default = None , help = 'the login file to use' )
parser . add_argument ( '-i' , '--infile' , dest = 'infile' , default = None , required = True , help = 'the input file name' )
parser . add_argument ( '-D' , '--DCname' , dest = 'dcname' , default = None , help = 'new datacenter name' )
# TODO : add / overwrite image password for creation
# parser . add _ argument ( ' - P ' , ' - - imagepassword ' , dest = ' imgpassword ' ,
# default = None , help = ' the image password ' )
parser . add_argument ( '-v' , '--verbose' , dest = "verbose" , action = "count" , default = 0 , help = "set verbosity level [default: %(default)s]" )
parser . add_argument ( '-V' , '--version' , action = 'version' , version = program_version_message )
# Process arguments
args = parser . parse_args ( )
global verbose
verbose = args . verbose
if verbose > 0 :
    print ( "Verbose mode on" )
    print ( "start {} with args {}" . format ( program_name , str ( args ) ) )
( user , password ) = getLogin ( args . loginfile , args . user , args . password )
if user is None or password is None :
    raise ValueError ( "user or password resolved to None" )
pbclient = ProfitBricksService ( user , password )
usefile = args . infile
print ( "read dc from {}" . format ( usefile ) )
dcdef = read_dc_definition ( usefile )
if verbose > 0 :
    print ( "using DC-DEF {}" . format ( json . dumps ( dcdef ) ) )
# setup dc :
# + create empty dc
# + create volumes ( unattached ) , map uuid to servers ( custom dict )
# + create servers
# + create nics
# + attach volumes
if 'custom' in dcdef and 'id' in dcdef [ 'custom' ] :
    dc_id = dcdef [ 'custom' ] [ 'id' ]
    print ( "using existing DC w/ id {}" . format ( str ( dc_id ) ) )
else :
    if args . dcname is not None :
        print ( "Overwrite DC name w/ '{}'" . format ( args . dcname ) )
        dcdef [ 'properties' ] [ 'name' ] = args . dcname
    dc = getDatacenterObject ( dcdef )
    # print ( " create DC { } " . format ( str ( dc ) ) )
    response = pbclient . create_datacenter ( dc )
    dc_id = response [ 'id' ]
    if 'custom' not in dcdef :
        dcdef [ 'custom' ] = dict ( )
    dcdef [ 'custom' ] [ 'id' ] = dc_id
    result = wait_for_request ( pbclient , response [ 'requestId' ] )
    print ( "wait loop returned {}" . format ( result ) )
    tmpfile = usefile + ".tmp_postdc"
    write_dc_definition ( dcdef , tmpfile )
requests = [ ]
print ( "create Volumes {}" . format ( str ( dc ) ) )
# we do NOT consider dangling volumes , only server - attached ones
for server in dcdef [ 'entities' ] [ 'servers' ] [ 'items' ] :
    print ( "- server {}" . format ( server [ 'properties' ] [ 'name' ] ) )
    if 'volumes' not in server [ 'entities' ] :
        print ( " server {} has no volumes" . format ( server [ 'properties' ] [ 'name' ] ) )
        continue
    for volume in server [ 'entities' ] [ 'volumes' ] [ 'items' ] :
        if 'custom' in volume and 'id' in volume [ 'custom' ] :
            vol_id = volume [ 'custom' ] [ 'id' ]
            print ( "using existing volume w/ id {}" . format ( str ( vol_id ) ) )
        else :
            dcvol = getVolumeObject ( volume )
            print ( "OBJ: {}" . format ( str ( dcvol ) ) )
            response = pbclient . create_volume ( dc_id , dcvol )
            volume . update ( { 'custom' : { 'id' : response [ 'id' ] } } )
            requests . append ( response [ 'requestId' ] )
    # end for ( volume )
# end for ( server )
if requests :
    result = wait_for_requests ( pbclient , requests , initial_wait = 10 , scaleup = 15 )
    print ( "wait loop returned {}" . format ( str ( result ) ) )
    tmpfile = usefile + ".tmp_postvol"
    write_dc_definition ( dcdef , tmpfile )
else :
    print ( "all volumes existed already" )
requests = [ ]
print ( "create Servers {}" . format ( str ( dc ) ) )
# we do NOT consider dangling volumes , only server - attached ones
for server in dcdef [ 'entities' ] [ 'servers' ] [ 'items' ] :
    print ( "- server {}" . format ( server [ 'properties' ] [ 'name' ] ) )
    if 'custom' in server and 'id' in server [ 'custom' ] :
        srv_id = server [ 'custom' ] [ 'id' ]
        print ( "using existing server w/ id {}" . format ( str ( srv_id ) ) )
    else :
        dcsrv = getServerObject ( server )
        print ( "OBJ: {}" . format ( str ( dcsrv ) ) )
        response = pbclient . create_server ( dc_id , dcsrv )
        server . update ( { 'custom' : { 'id' : response [ 'id' ] } } )
        requests . append ( response [ 'requestId' ] )
# end for ( server )
if requests :
    result = wait_for_requests ( pbclient , requests , initial_wait = 10 , scaleup = 15 )
    print ( "wait loop returned {}" . format ( str ( result ) ) )
    tmpfile = usefile + ".tmp_postsrv"
    write_dc_definition ( dcdef , tmpfile )
else :
    print ( "all servers existed already" )
# TODO : only do this if we have lan entities
requests = [ ]
# Huuh , looks like we get unpredictable order for LANs !
# Nope , order of creation determines the LAN id ,
# thus we better wait for each request
print ( "create LANs {}" . format ( str ( dc ) ) )
for lan in dcdef [ 'entities' ] [ 'lans' ] [ 'items' ] :
    print ( "- lan {}" . format ( lan [ 'properties' ] [ 'name' ] ) )
    dclan = getLANObject ( lan )
    print ( "OBJ: {}" . format ( str ( dclan ) ) )
    response = pbclient . create_lan ( dc_id , dclan )
    lan . update ( { 'custom' : { 'id' : response [ 'id' ] } } )
    result = wait_for_request ( pbclient , response [ 'requestId' ] )
    print ( "wait loop returned {}" . format ( str ( result ) ) )
# end for ( lan )
tmpfile = usefile + ".tmp_postlan"
write_dc_definition ( dcdef , tmpfile )
requests = [ ]
# Attention :
# NICs appear in OS in the order , they are created .
# But DCD rearranges the display by ascending MAC addresses .
# This does not change the OS order .
# MAC may not be available from create response ,
# thus we wait for each request : - (
print ( "create NICs {}" . format ( str ( dc ) ) )
for server in dcdef [ 'entities' ] [ 'servers' ] [ 'items' ] :
    print ( "- server {}" . format ( server [ 'properties' ] [ 'name' ] ) )
    srv_id = server [ 'custom' ] [ 'id' ]
    if 'nics' not in server [ 'entities' ] :
        print ( " server {} has no NICs" . format ( server [ 'properties' ] [ 'name' ] ) )
        continue
    macmap = dict ( )
    for nic in server [ 'entities' ] [ 'nics' ] [ 'items' ] :
        dcnic = getNICObject ( nic )
        response = pbclient . create_nic ( dc_id , srv_id , dcnic )
        # print ( " dcnic response { } " . format ( str ( response ) ) )
        # mac = response [ ' properties ' ] [ ' mac ' ] # we don ' t get it here ! ?
        nic_id = response [ 'id' ]
        result = wait_for_request ( pbclient , response [ 'requestId' ] )
        print ( "wait loop returned {}" . format ( str ( result ) ) )
        response = pbclient . get_nic ( dc_id , srv_id , nic_id , 2 )
        mac = response [ 'properties' ] [ 'mac' ]
        print ( "dcnic has MAC {} for {}" . format ( mac , nic_id ) )
        macmap [ mac ] = nic_id
    # end for ( nic )
    macs = sorted ( macmap )
    print ( "macs will be displayed by DCD in th following order:" )
    for mac in macs :
        print ( "mac {} -> id{}" . format ( mac , macmap [ mac ] ) )
# end for ( server )
tmpfile = usefile + ".tmp_postnic"
write_dc_definition ( dcdef , tmpfile )
requests = [ ]
# don ' t know if we get a race here too , so better wait for each request : - /
print ( "attach volumes {}" . format ( str ( dc ) ) )
for server in dcdef [ 'entities' ] [ 'servers' ] [ 'items' ] :
    print ( "- server {}" . format ( server [ 'properties' ] [ 'name' ] ) )
    if 'volumes' not in server [ 'entities' ] :
        print ( " server {} has no volumes" . format ( server [ 'properties' ] [ 'name' ] ) )
        continue
    srv_id = server [ 'custom' ] [ 'id' ]
    for volume in server [ 'entities' ] [ 'volumes' ] [ 'items' ] :
        print ( "OBJ: {}" . format ( volume [ 'properties' ] [ 'name' ] ) )
        response = pbclient . attach_volume ( dc_id , srv_id , volume [ 'custom' ] [ 'id' ] )
        result = wait_for_request ( pbclient , response [ 'requestId' ] )
        print ( "wait loop returned {}" . format ( str ( result ) ) )
    # end for ( volume )
# end for ( server )
tmpfile = usefile + ".tmp_postatt"
write_dc_definition ( dcdef , tmpfile )
# TODO : do we need to set boot volume for each server ?
# looks like it ' s working without
return 0


signature:
def getServerInfo ( pbclient = None , dc_id = None ) :
    '''gets info of servers of a data center'''

implementation:
if pbclient is None :
    raise ValueError ( "argument 'pbclient' must not be None" )
if dc_id is None :
    raise ValueError ( "argument 'dc_id' must not be None" )
# list of all found server ' s info
server_info = [ ]
# depth 1 is enough for props / meta
servers = pbclient . list_servers ( dc_id , 1 )
for server in servers [ 'items' ] :
    props = server [ 'properties' ]
    info = dict ( id = server [ 'id' ] , name = props [ 'name' ] , state = server [ 'metadata' ] [ 'state' ] , vmstate = props [ 'vmState' ] )
    server_info . append ( info )
# end for ( servers )
return server_info


signature:
def getServerStates ( pbclient = None , dc_id = None , serverid = None , servername = None ) :
    '''gets states of a server'''

implementation:
if pbclient is None :
    raise ValueError ( "argument 'pbclient' must not be None" )
if dc_id is None :
    raise ValueError ( "argument 'dc_id' must not be None" )
server = None
if serverid is None :
    if servername is None :
        raise ValueError ( "one of 'serverid' or 'servername' must be specified" )
    # so , arg . servername is set ( to whatever )
    server_info = select_where ( getServerInfo ( pbclient , dc_id ) , [ 'id' , 'name' , 'state' , 'vmstate' ] , name = servername )
    if len ( server_info ) > 1 :
        raise NameError ( "ambiguous server name '{}'" . format ( servername ) )
    if len ( server_info ) == 1 :
        server = server_info [ 0 ]
else : # get by ID may also fail if it ' s removed
# in this case , catch exception ( message 404 ) and be quiet for a while
# unfortunately this has changed from Py2 to Py3
    try :
        server_info = pbclient . get_server ( dc_id , serverid , 1 )
        server = dict ( id = server_info [ 'id' ] , name = server_info [ 'properties' ] [ 'name' ] , state = server_info [ 'metadata' ] [ 'state' ] , vmstate = server_info [ 'properties' ] [ 'vmState' ] )
    except Exception :
        ex = sys . exc_info ( ) [ 1 ]
        if ex . args [ 0 ] is not None and ex . args [ 0 ] == 404 :
            print ( "Server w/ ID {} not found" . format ( serverid ) )
            server = None
        else :
            raise ex
    # end try / except
# end if / else ( serverid )
return server


signature:
def wait_for_server ( pbclient = None , dc_id = None , serverid = None , indicator = 'state' , state = 'AVAILABLE' , timeout = 300 ) :
    '''wait for a server / VM to reach a defined state for a specified time
 indicator : = { state | vmstate } specifies if server or VM stat is tested
 state specifies the status the indicator should have'''

implementation:
if pbclient is None :
    raise ValueError ( "argument 'pbclient' must not be None" )
if dc_id is None :
    raise ValueError ( "argument 'dc_id' must not be None" )
if serverid is None :
    raise ValueError ( "argument 'serverid' must not be None" )
total_sleep_time = 0
seconds = 5
while total_sleep_time < timeout :
    time . sleep ( seconds )
    total_sleep_time += seconds
    if total_sleep_time == 60 : # Increase polling interval after one minute
        seconds = 10
    elif total_sleep_time == 600 : # Increase polling interval after 10 minutes
        seconds = 20
    server = getServerStates ( pbclient , dc_id , serverid )
    if server [ indicator ] == state :
        break
# end while ( total _ sleep _ time )
return server


signature:
def wait_for_datacenter ( client , data_center_id ) :
    '''Poll the data center to become available ( for the next provisionig job )'''

implementation:
total_sleep_time = 0
seconds = 5
while True :
    state = client . get_datacenter ( data_center_id ) [ 'metadata' ] [ 'state' ]
    if verbose :
        print ( "datacenter is {}" . format ( state ) )
    if state == "AVAILABLE" :
        break
    time . sleep ( seconds )
    total_sleep_time += seconds
    if total_sleep_time == 60 : # Increase polling interval after one minute
        seconds = 10
    elif total_sleep_time == 600 : # Increase polling interval after 10 minutes
        seconds = 20


signature:
def main ( argv = None ) :
    '''Command line options .'''

implementation:
if argv is None :
    argv = sys . argv
else :
    sys . argv . extend ( argv )
program_name = os . path . basename ( sys . argv [ 0 ] )
program_version = "v%s" % __version__
program_build_date = str ( __updated__ )
program_version_message = '%%(prog)s %s (%s)' % ( program_version , program_build_date )
program_shortdesc = __import__ ( '__main__' ) . __doc__ . split ( "\n" ) [ 1 ]
program_license = '''%s

  Created by J. Buchhammer on %s.
  Copyright 2016 ProfitBricks GmbH. All rights reserved.

  Licensed under the Apache License 2.0
  http://www.apache.org/licenses/LICENSE-2.0

  Distributed on an "AS IS" basis without warranties
  or conditions of any kind, either express or implied.

USAGE
''' % ( program_shortdesc , str ( __date__ ) )
try : # Setup argument parser
    parser = ArgumentParser ( description = program_license , formatter_class = RawDescriptionHelpFormatter )
    parser . add_argument ( '-u' , '--user' , dest = 'user' , help = 'the login name' )
    parser . add_argument ( '-p' , '--password' , dest = 'password' , help = 'the login password' )
    parser . add_argument ( '-L' , '--Login' , dest = 'loginfile' , default = None , help = 'the login file to use' )
    parser . add_argument ( '-d' , '--datacenterid' , dest = 'dc_id' , required = True , default = None , help = 'datacenter of the server' )
    parser . add_argument ( '-s' , '--serverid' , dest = 'serverid' , default = None , help = 'ID of the server' )
    parser . add_argument ( '-n' , '--name' , dest = 'servername' , default = None , help = 'name of the server' )
    parser . add_argument ( '-C' , '--command' , dest = 'command' , default = None , help = 'remote shell command to use for shutdown' )
    parser . add_argument ( '-v' , '--verbose' , dest = "verbose" , action = "count" , help = "set verbosity level [default: %(default)s]" )
    parser . add_argument ( '-V' , '--version' , action = 'version' , version = program_version_message )
    # Process arguments
    args = parser . parse_args ( )
    global verbose
    verbose = args . verbose
    dc_id = args . dc_id
    if verbose > 0 :
        print ( "Verbose mode on" )
    if args . serverid is None and args . servername is None :
        parser . error ( "one of 'serverid' or 'name' must be specified" )
    ( user , password ) = getLogin ( args . loginfile , args . user , args . password )
    if user is None or password is None :
        raise ValueError ( "user or password resolved to None" )
    pbclient = ProfitBricksService ( user , password )
    server = getServerStates ( pbclient , dc_id , args . serverid , args . servername )
    if server is None :
        raise Exception ( 1 , "specified server not found" )
    print ( "using server {}(id={}) in state {}, {}" . format ( server [ 'name' ] , server [ 'id' ] , server [ 'state' ] , server [ 'vmstate' ] ) )
    # ! stop / start / reboot _ server ( ) simply return ' True ' !
    # this implies , that there ' s NO response nor requestId to track !
    if server [ 'vmstate' ] == 'SHUTOFF' :
        print ( "VM is already shut off" )
    else :
        if args . command is None :
            print ( "no command specified for shutdown of VM" )
        else :
            print ( "executing {}" . format ( args . command ) )
            cmdrc = call ( args . command , shell = True )
            print ( "executing {} returned {}" . format ( args . command , cmdrc ) )
            server = wait_for_server ( pbclient , dc_id , server [ 'id' ] , indicator = 'vmstate' , state = 'SHUTOFF' , timeout = 300 )
    # first we have to delete all attached volumes
    volumes = pbclient . get_attached_volumes ( dc_id , server [ 'id' ] , 0 )
    for vol in volumes [ 'items' ] :
        print ( "deleting volume {} of server {}" . format ( vol [ 'id' ] , server [ 'name' ] ) )
        pbclient . delete_volume ( dc_id , vol [ 'id' ] )
    pbclient . delete_server ( dc_id , server [ 'id' ] )
    wait_for_datacenter ( pbclient , dc_id )
except KeyboardInterrupt : # handle keyboard interrupt #
    pass
except Exception :
    traceback . print_exc ( )
    sys . stderr . write ( "\n" + program_name + ":  for help use --help\n" )
    return 2
return 0


signature:
def getLogin ( filename , user , passwd ) :
    '''write user / passwd to login file or get them from file .
 This method is not Py3 safe ( byte vs . str )'''

implementation:
if filename is None :
    return ( user , passwd )
if os . path . exists ( filename ) :
    print ( "Using file {} for Login" . format ( filename ) )
    with open ( filename , "r" ) as loginfile :
        encoded_cred = loginfile . read ( )
        decoded_cred = b64decode ( encoded_cred )
        login = decoded_cred . split ( ':' , 1 )
        return ( login [ 0 ] , login [ 1 ] )
else :
    if user is None or passwd is None :
        raise ValueError ( "user and password must not be None" )
    print ( "Writing file {} for Login" . format ( filename ) )
    with open ( filename , "w" ) as loginfile :
        encoded_cred = b64encode ( user + ":" + passwd )
        loginfile . write ( encoded_cred )
    return ( user , passwd )


signature:
def wait_for_request ( pbclient , request_id , timeout = 0 , initial_wait = 5 , scaleup = 10 ) :
    '''Waits for a request to finish until timeout .
 timeout = = 0 is interpreted as infinite wait time .
 Returns a tuple ( return code , request status , message ) where return code
 0 : request successful
 1 : request failed
 -1 : timeout exceeded
 The wait _ period is increased every scaleup steps to adjust for long
 running requests .'''

implementation:
total_wait = 0
wait_period = initial_wait
next_scaleup = scaleup * wait_period
wait = True
while wait :
    request_status = pbclient . get_request ( request_id , status = True )
    state = request_status [ 'metadata' ] [ 'status' ]
    if state == "DONE" :
        return ( 0 , state , request_status [ 'metadata' ] [ 'message' ] )
    if state == 'FAILED' :
        return ( 1 , state , request_status [ 'metadata' ] [ 'message' ] )
    if verbose > 0 :
        print ( "Request '{}' is in state '{}'. Sleeping for {} seconds..." . format ( request_id , state , wait_period ) )
    sleep ( wait_period )
    total_wait += wait_period
    if timeout != 0 and total_wait > timeout :
        wait = False
    next_scaleup -= wait_period
    if next_scaleup == 0 :
        wait_period += initial_wait
        next_scaleup = scaleup * wait_period
        if verbose > 0 :
            print ( "scaling up wait_period to {}, next change in {} seconds" . format ( wait_period , next_scaleup ) )
# end while ( wait )
return ( - 1 , state , "request not finished before timeout" )


implementation:
if argv is None :
    argv = sys . argv
else :
    sys . argv . extend ( argv )
program_name = os . path . basename ( sys . argv [ 0 ] )
program_version = "v%s" % __version__
program_build_date = str ( __updated__ )
program_version_message = '%%(prog)s %s (%s)' % ( program_version , program_build_date )
program_shortdesc = __import__ ( '__main__' ) . __doc__ . split ( "\n" ) [ 1 ]
program_license = '''%s

  Created by J. Buchhammer on %s.
  Copyright 2016 ProfitBricks GmbH. All rights reserved.

  Licensed under the Apache License 2.0
  http://www.apache.org/licenses/LICENSE-2.0

  Distributed on an "AS IS" basis without warranties
  or conditions of any kind, either express or implied.

USAGE
''' % ( program_shortdesc , str ( __date__ ) )
try : # Setup argument parser
    parser = ArgumentParser ( description = program_license , formatter_class = RawDescriptionHelpFormatter )
    parser . add_argument ( '-u' , '--user' , dest = 'user' , help = 'the login name' )
    parser . add_argument ( '-p' , '--password' , dest = 'password' , help = 'the login password' )
    parser . add_argument ( '-L' , '--Login' , dest = 'loginfile' , default = None , help = 'the login file to use' )
    parser . add_argument ( '-d' , '--datacenterid' , dest = 'datacenterid' , required = True , default = None , help = 'datacenter of the new server' )
    parser . add_argument ( '-l' , '--lanid' , dest = 'lanid' , required = True , default = None , help = 'LAN of the new server' )
    parser . add_argument ( '-n' , '--name' , dest = 'servername' , default = "SRV_" + datetime . now ( ) . isoformat ( ) , help = 'name of the new server' )
    parser . add_argument ( '-c' , '--cores' , dest = 'cores' , type = int , default = 2 , help = 'CPU cores' )
    parser . add_argument ( '-r' , '--ram' , dest = 'ram' , type = int , default = 4 , help = 'RAM in GB' )
    parser . add_argument ( '-s' , '--storage' , dest = 'storage' , type = int , default = 4 , help = 'storage in GB' )
    parser . add_argument ( '-b' , '--boot' , dest = 'bootdevice' , default = "HDD" , help = 'boot device' )
    parser . add_argument ( '-i' , '--imageid' , dest = 'imageid' , default = None , help = 'installation image' )
    parser . add_argument ( '-P' , '--imagepassword' , dest = 'imgpassword' , default = None , help = 'the image password' )
    parser . add_argument ( '-v' , '--verbose' , dest = "verbose" , action = "count" , help = "set verbosity level [default: %(default)s]" )
    parser . add_argument ( '-V' , '--version' , action = 'version' , version = program_version_message )
    # Process arguments
    args = parser . parse_args ( )
    global verbose
    verbose = args . verbose
    dc_id = args . datacenterid
    lan_id = args . lanid
    servername = args . servername
    if verbose > 0 :
        print ( "Verbose mode on" )
        print ( "start {} with args {}" . format ( program_name , str ( args ) ) )
    # Test images ( location de / fra )
    # CDROM : 7fc885b3 - c9a6-11e5 - aa10-52540005ab80 # debian - 8.3.0 - amd64 - netinst . iso
    # HDD : 28007a6d - c88a - 11e5 - aa10-52540005ab80 # CentOS - 7 - server - 2016-02-01
    hdimage = args . imageid
    cdimage = None
    if args . bootdevice == "CDROM" :
        hdimage = None
        cdimage = args . imageid
    print ( "using boot device {} with image {}" . format ( args . bootdevice , args . imageid ) )
    ( user , password ) = getLogin ( args . loginfile , args . user , args . password )
    if user is None or password is None :
        raise ValueError ( "user or password resolved to None" )
    pbclient = ProfitBricksService ( user , password )
    first_nic = NIC ( name = "local" , ips = [ ] , dhcp = True , lan = lan_id )
    volume = Volume ( name = servername + "-Disk" , size = args . storage , image = hdimage , image_password = args . imgpassword )
    server = Server ( name = servername , cores = args . cores , ram = args . ram * 1024 , create_volumes = [ volume ] , nics = [ first_nic ] , boot_cdrom = cdimage )
    print ( "creating server.." )
    if verbose > 0 :
        print ( "SERVER: {}" . format ( str ( server ) ) )
    response = pbclient . create_server ( dc_id , server )
    print ( "wait for provisioning.." )
    wait_for_request ( pbclient , response [ "requestId" ] )
    server_id = response [ 'id' ]
    print ( "Server provisioned with ID {}" . format ( server_id ) )
    nics = pbclient . list_nics ( dc_id , server_id , 1 )
    # server should have exactly one nic , but we only test empty nic list
    if not nics [ 'items' ] :
        raise CLIError ( "No NICs found for newly created server {}" . format ( server_id ) )
    nic0 = nics [ 'items' ] [ 0 ]
    if verbose > 0 :
        print ( "NIC0: {}" . format ( str ( nic0 ) ) )
    ( nic_id , nic_mac ) = ( nic0 [ 'id' ] , nic0 [ 'properties' ] [ 'mac' ] )
    print ( "NIC of new Server has ID {} and MAC {}" . format ( nic_id , nic_mac ) )
    print ( "{} finished w/o errors" . format ( program_name ) )
    return 0
except KeyboardInterrupt : # handle keyboard interrupt #
    return 0
except Exception :
    traceback . print_exc ( )
    sys . stderr . write ( "\n" + program_name + ":  for help use --help\n" )
    return 2