def test_acquire_wan_vessels_multiple_calls_rand(self): # Have every vessel acquisition to the backend request succeed. calls_results = [True] * 10 mocklib.mock_backend_acquire_vessel(calls_results) # Create a user who will be doing the acquiring. user = maindb.create_user("testuser", "password", "*****@*****.**", "affiliation", "1 2", "2 2 2", "3 4") userport = user.usable_vessel_port vesselcount = maindb.get_user_free_vessel_credits(user) # Create vesselcount nodes split between the different types. testutil.create_nodes_on_different_subnets(4, [userport]) testutil.create_nodes_on_same_subnet(4, [userport]) testutil.create_nat_nodes(vesselcount - 8, [userport]) # First request a single vessel. first_vessel_list = interface.acquire_vessels(user, 1, 'rand') # Now acquire all of the rest that the user can acquire. second_vessel_list = interface.acquire_vessels(user, vesselcount - 1, 'rand') self.assertEqual(1, len(first_vessel_list)) self.assertEqual(vesselcount - 1, len(second_vessel_list))
def test_acquire_wan_vessels_some_vessels_fail(self): # Have every other vessel acquisition fail. We're going to acquire 50, # so we'll need 100 responses alternating between failure and success # (we're starting with failure, so 100, not 99). calls_results = [False, True] * 50 mocklib.mock_backend_acquire_vessel(calls_results) # Create a user who will be doing the acquiring. user = maindb.create_user("testuser", "password", "*****@*****.**", "affiliation", "1 2", "2 2 2", "3 4") userport = user.usable_vessel_port # We need to give the user some donations so they have enough credits. # We're assuming it's 10 credits per donation. self.assertEqual(10, maindb.VESSEL_CREDITS_FOR_DONATIONS_MULTIPLIER) # Also make sure the user started with 10 credits. self.assertEqual(10, maindb.get_user_free_vessel_credits(user)) # We need 100 nodes the user can acquire vessels on as we're having half of # the node acquisitions fail. testutil.create_nodes_on_different_subnets(100, [userport]) # Now credit the user for donations on 4 of these. for node in maindb.get_active_nodes()[:4]: maindb.create_donation(node, user, '') # Ok, the user now has 50 vessels the can acquire and there are 100 nodes # with vessels available for them. Let's try to acquire all 50 at once and # make sure this works even though we'll have to get through 100 requests # to the backend to make it happen. vessel_list = interface.acquire_vessels(user, 50, 'wan') self.assertEqual(50, len(vessel_list))
def get_resources(request): try: user = _validate_and_get_geniuser(request) except LoggedInButFailedGetGeniUserError: return _show_failed_get_geniuser_page(request) # the request must be via POST. if not, bounce user back to My Vessels page if not request.method == 'POST': return myvessels(request) # try and grab form from POST. if it can't, bounce user back to My Vessels page get_form = forms.gen_get_form(user, request.POST) action_summary = "" action_detail = "" keep_get_form = False if get_form.is_valid(): vessel_num = get_form.cleaned_data['num'] vessel_type = get_form.cleaned_data['env'] try: acquired_vessels = interface.acquire_vessels(user, vessel_num, vessel_type) except UnableToAcquireResourcesError, err: action_summary = "Unable to acquire vessels at this time." if str(err) == 'Acquiring NAT vessels is currently disabled. ': link = """<a href="{{ TESTBED_URL }}}blog">blog</a>""" action_detail += str(err) + 'Please check our '+ link +' to see when we have re-enabled NAT vessels.' else: action_detail += str(err) keep_get_form = True except InsufficientUserResourcesError: action_summary = "Unable to acquire vessels: you do not have enough vessel credits to fulfill this request." keep_get_form = True
def test_renew_some_of_users_vessel(self): # Create a user who will be doing the acquiring. user = maindb.create_user("testuser", "password", "*****@*****.**", "affiliation", "1 2", "2 2 2", "3 4") userport = user.usable_vessel_port vesselcount = 4 # Have every vessel acquisition to the backend request succeed. calls_results = [True] * vesselcount mocklib.mock_backend_acquire_vessel(calls_results) testutil.create_nodes_on_different_subnets(vesselcount, [userport]) # Acquire all of the vessels the user can acquire. vessel_list = interface.acquire_vessels(user, vesselcount, 'rand') renew_vessels_list = vessel_list[:2] not_renewed_vessels_list = vessel_list[2:] interface.renew_vessels(user, renew_vessels_list) now = datetime.datetime.now() timedelta_oneday = datetime.timedelta(days=1) for vessel in renew_vessels_list: self.assertTrue(vessel.date_expires - now > timedelta_oneday) for vessel in not_renewed_vessels_list: self.assertTrue(vessel.date_expires - now < timedelta_oneday)
def test_renew_vessels_insufficient_vessel_credits(self): # Create a user who will be doing the acquiring. user = maindb.create_user("testuser", "password", "*****@*****.**", "affiliation", "1 2", "2 2 2", "3 4") userport = user.usable_vessel_port vesselcount = 4 # Have every vessel acquisition to the backend request succeed. calls_results = [True] * vesselcount mocklib.mock_backend_acquire_vessel(calls_results) testutil.create_nodes_on_different_subnets(vesselcount, [userport]) # Acquire all of the vessels the user can acquire. vessel_list = interface.acquire_vessels(user, vesselcount, 'rand') # Decrease the user's vessel credits to one less than the number of vessels # they have acquired. user.free_vessel_credits = 0 user.save() func = interface.renew_vessels args = (user, vessel_list) self.assertRaises(InsufficientUserResourcesError, func, *args) func = interface.renew_all_vessels args = (user,) self.assertRaises(InsufficientUserResourcesError, func, *args)
def acquire_resources(auth, rspec): """ <Purpose> Acquires resources for users over XMLRPC. <Arguments> auth An authorization dict. rspec A resource specification dict of the form {'rspec_type':type, 'number_of_nodes':num} <Exceptions> Raises xmlrpclib Fault objects: FAULTCODE_INTERNALERROR for internal errors. FAULTCODE_INVALIDREQUEST for bad user input. FAULTCODE_NOTENOUGHCREDITS if user has insufficient vessel credits to complete request. <Returns> A list of 'info' dictionaries, each 'infodict' contains acquired vessel info. """ geni_user = _auth(auth) if not isinstance(rspec, dict): raise xmlrpclib.Fault(FAULTCODE_INVALIDREQUEST, "rspec is an invalid data type.") try: resource_type = rspec['rspec_type'] except KeyError: raise xmlrpclib.Fault(FAULTCODE_INVALIDREQUEST, "rspec is missing rspec_type") try: num_vessels = rspec['number_of_nodes'] except KeyError: raise xmlrpclib.Fault(FAULTCODE_INVALIDREQUEST, "rspec is missing number_of_nodes") acquired_vessels = [] # validate rspec data if not isinstance(resource_type, str) or not isinstance( num_vessels, int): raise xmlrpclib.Fault(FAULTCODE_INVALIDREQUEST, "rspec has invalid data types.") if resource_type not in ['wan', 'lan', 'nat', 'random' ] or num_vessels < 1: raise xmlrpclib.Fault(FAULTCODE_INVALIDREQUEST, "rspec has invalid values.") # The interface.acquire_vessels() call expects 'rand' instead of 'random'. if resource_type == 'random': resource_type = 'rand' try: acquired_vessels = interface.acquire_vessels( geni_user, num_vessels, resource_type) except UnableToAcquireResourcesError, err: raise xmlrpclib.Fault( FAULTCODE_UNABLETOACQUIRE, "Unable to fulfill vessel acquire request at this given time. Details: " + str(err))
def test_regenerate_user_key(self): pubkey = "1 2" privkey = "3 4 5" donor_key = "6 7" # Create a user who will be doing the acquiring. user = maindb.create_user("testuser", "password", "*****@*****.**", "affiliation", pubkey, privkey, donor_key) userport = user.usable_vessel_port vesselcount = 4 # Have every vessel acquisition to the backend request succeed. calls_results = [True] * vesselcount mocklib.mock_backend_acquire_vessel(calls_results) testutil.create_nodes_on_different_subnets(vesselcount, [userport]) # Acquire all vessels on behalf of this user. all_vessels_list = interface.acquire_vessels(user, vesselcount, 'rand') # Release 2 vessels. released_vessels_list = all_vessels_list[:2] kept_vessels_list = all_vessels_list[2:] interface.release_vessels(user, released_vessels_list) # Ensure all of the vessels are marked as having user keys in sync. for vessel in all_vessels_list: # Get a fresh vessel from the db. vessel = maindb.get_vessel(vessel.node.node_identifier, vessel.name) self.assertTrue(vessel.user_keys_in_sync) # We expect a single key to be generated through the keygen api (the new # user public key). mocklib.mock_keygen_generate_keypair([("55 66", "77 88 99")]) interface.change_user_keys(user, pubkey=None) # Get a new user object from the database. user = maindb.get_user(user.username) # Make sure the user's key changed. self.assertEqual(user.user_pubkey, "55 66") self.assertEqual(user.user_privkey, "77 88 99") # Make sure that all of the vessels the user has access to (and no other # vessels) are marked as needing user keys to be sync'd. # Ensure all of the vessels are marked as having user keys in sync. for vessel in kept_vessels_list: # Get a fresh vessel from the db. vessel = maindb.get_vessel(vessel.node.node_identifier, vessel.name) self.assertFalse(vessel.user_keys_in_sync) for vessel in released_vessels_list: # Get a fresh vessel from the db. vessel = maindb.get_vessel(vessel.node.node_identifier, vessel.name) self.assertTrue(vessel.user_keys_in_sync)
def test_renew_vessels_dont_belong_to_user(self): # Create a user who will be doing the acquiring. user = maindb.create_user("testuser", "password", "*****@*****.**", "affiliation", "1 2", "2 2 2", "3 4") userport = user.usable_vessel_port # Create a second user. user2 = maindb.create_user("user2", "password", "*****@*****.**", "affiliation", "1 2", "2 2 2", "3 4") vesselcount = 4 # Have every vessel acquisition to the backend request succeed. calls_results = [True] * vesselcount mocklib.mock_backend_acquire_vessel(calls_results) testutil.create_nodes_on_different_subnets(vesselcount, [userport]) # Acquire all of the vessels the user can acquire. vessel_list = interface.acquire_vessels(user, vesselcount, 'rand') release_vessel = vessel_list[0] interface.release_vessels(user, [release_vessel]) # Manually fiddle with one of the vessels to make it owned by user2. user2_vessel = vessel_list[1] user2_vessel.acquired_by_user = user2 user2_vessel.save() # Try to renew all of the originally acquired vessels, including the ones # that were released. We expect these to just be ignored. interface.renew_vessels(user, vessel_list) # Get fresh vessel objects that reflect the renewal. remaining_vessels = interface.get_acquired_vessels(user) release_vessel = maindb.get_vessel(release_vessel.node.node_identifier, release_vessel.name) user2_vessel = maindb.get_vessel(user2_vessel.node.node_identifier, user2_vessel.name) now = datetime.datetime.now() timedelta_oneday = datetime.timedelta(days=1) # Ensure that the vessels the user still has were renewed but that the ones # the user released were ignored (not renewed). for vessel in remaining_vessels: self.assertTrue(vessel.date_expires - now > timedelta_oneday) self.assertTrue(user2_vessel.date_expires - now < timedelta_oneday) self.assertEqual(release_vessel.date_expires, None)
def test_acquire_lan_vessels_some_subnets_have_too_many_vessels_fail(self): """ We're going to be trying to acquire 4 vessels in a single subnet. We'll make it so that there are 3 subnets to choose from. The first two will potentially have enough vessels for the user to satisfy their acquisition request, but too many vessels in each will fail. The third subnet tried will have enough succeed. """ # We're going to have three subnets with 5 potential vessels each. We # want the first two subnets to fail. Choosing the values creatively # here is helped by knowing the logic of the function # vessels._acquire_vessels_from_list(). Basically, it won't try to # acquire more than the minumum needed at a time, so the first time # it loops it will try to acquire all 4, then the next time it loops # it will try to acquire however many of the 4 failed the first time. # It won't bother trying again if there are too few left in the list. results_1 = [False, True, True, True, False] results_2 = [False, False, True, True] results_3 = [False, True, True, True, True] calls_results = results_1 + results_2 + results_3 mocklib.mock_backend_acquire_vessel(calls_results) # Create a user who will be doing the acquiring. user = maindb.create_user("testuser", "password", "*****@*****.**", "affiliation", "1 2", "2 2 2", "3 4") userport = user.usable_vessel_port # Make sure the user starts with 10 credits. self.assertEqual(10, maindb.get_user_free_vessel_credits(user)) # Create three subnets with 5 nodes each. We need to keep them all the same # size, otherwise we need to change the test to patch maindb so that the # subnets will be tried in the order we expect. testutil.create_nodes_on_same_subnet(5, [userport], ip_prefix="127.0.0.") testutil.create_nodes_on_same_subnet(5, [userport], ip_prefix="127.0.1.") testutil.create_nodes_on_same_subnet(5, [userport], ip_prefix="127.0.2.") # Now try to acquire 8 lan nodes on a single subnet. vessel_list = interface.acquire_vessels(user, 4, 'lan') self.assertEqual(4, len(vessel_list)) # Make sure backend.acquire_vessel() got called the correct number of # times (that is, the call_results list got pop(0)'d enough times). self.assertEqual(0, len(calls_results))
def acquire_resources(auth, rspec): """ <Purpose> Acquires resources for users over XMLRPC. <Arguments> auth An authorization dict. rspec A resource specification dict of the form {'rspec_type':type, 'number_of_nodes':num} <Exceptions> Raises xmlrpclib Fault objects: FAULTCODE_INTERNALERROR for internal errors. FAULTCODE_INVALIDREQUEST for bad user input. FAULTCODE_NOTENOUGHCREDITS if user has insufficient vessel credits to complete request. <Returns> A list of 'info' dictionaries, each 'infodict' contains acquired vessel info. """ geni_user = _auth(auth) if not isinstance(rspec, dict): raise xmlrpclib.Fault(FAULTCODE_INVALIDREQUEST, "rspec is an invalid data type.") try: resource_type = rspec['rspec_type'] except KeyError: raise xmlrpclib.Fault(FAULTCODE_INVALIDREQUEST, "rspec is missing rspec_type") try: num_vessels = rspec['number_of_nodes'] except KeyError: raise xmlrpclib.Fault(FAULTCODE_INVALIDREQUEST, "rspec is missing number_of_nodes") acquired_vessels = [] # validate rspec data if not isinstance(resource_type, str) or not isinstance(num_vessels, int): raise xmlrpclib.Fault(FAULTCODE_INVALIDREQUEST, "rspec has invalid data types.") if resource_type not in ['wan', 'lan', 'nat', 'random'] or num_vessels < 1: raise xmlrpclib.Fault(FAULTCODE_INVALIDREQUEST, "rspec has invalid values.") # The interface.acquire_vessels() call expects 'rand' instead of 'random'. if resource_type == 'random': resource_type = 'rand' try: acquired_vessels = interface.acquire_vessels(geni_user, num_vessels, resource_type) except UnableToAcquireResourcesError, err: raise xmlrpclib.Fault(FAULTCODE_UNABLETOACQUIRE, "Unable to fulfill vessel acquire request at this given time. Details: " + str(err))
def test_set_user_key(self): pubkey = "1 2" privkey = "3 4 5" donor_key = "6 7" # Create a user who will be doing the acquiring. user = maindb.create_user("testuser", "password", "*****@*****.**", "affiliation", pubkey, privkey, donor_key) userport = user.usable_vessel_port vesselcount = 4 # Have every vessel acquisition to the backend request succeed. calls_results = [True] * vesselcount mocklib.mock_backend_acquire_vessel(calls_results) testutil.create_nodes_on_different_subnets(vesselcount, [userport]) # Acquire all vessels on behalf of this user. all_vessels_list = interface.acquire_vessels(user, vesselcount, 'rand') # Release 2 vessels. released_vessels_list = all_vessels_list[:2] kept_vessels_list = all_vessels_list[2:] interface.release_vessels(user, released_vessels_list) # Ensure all of the vessels are marked as having user keys in sync. for vessel in all_vessels_list: # Get a fresh vessel from the db. vessel = maindb.get_vessel(vessel.node.node_identifier, vessel.name) self.assertTrue(vessel.user_keys_in_sync) # We expect no keys to be generated through the keygen api. mocklib.mock_keygen_generate_keypair([]) interface.change_user_keys(user, pubkey="55 66") # Get a new user object from the database. user = maindb.get_user(user.username) # Make sure the user's key changed. self.assertEqual(user.user_pubkey, "55 66") self.assertEqual(user.user_privkey, None) # Make sure that all of the vessels the user has access to (and no other # vessels) are marked as needing user keys to be sync'd. # Ensure all of the vessels are marked as having user keys in sync. for vessel in kept_vessels_list: # Get a fresh vessel from the db. vessel = maindb.get_vessel(vessel.node.node_identifier, vessel.name) self.assertFalse(vessel.user_keys_in_sync) for vessel in released_vessels_list: # Get a fresh vessel from the db. vessel = maindb.get_vessel(vessel.node.node_identifier, vessel.name) self.assertTrue(vessel.user_keys_in_sync)