فهرست منبع

Merge pull request #115 from Dany9966/licensing-updates

Update licensing client for v2.
Nashwan Azhari 5 سال پیش
والد
کامیت
ed7b518566
2فایلهای تغییر یافته به همراه93 افزوده شده و 22 حذف شده
  1. 35 6
      coriolis/conductor/rpc/server.py
  2. 58 16
      coriolis/licensing/client.py

+ 35 - 6
coriolis/conductor/rpc/server.py

@@ -331,7 +331,8 @@ class ConductorServerEndpoint(object):
             transfer_type, ninstances)
         transfer_action.reservation_id = reservation['id']
 
-    def _check_reservation_for_transfer(self, transfer_action):
+    def _check_reservation_for_transfer(
+            self, transfer_action, reservation_type):
         action_id = transfer_action.base_id
         if not self._licensing_client:
             LOG.warn(
@@ -344,11 +345,37 @@ class ConductorServerEndpoint(object):
             LOG.debug(
                 "Attempting to check reservation with ID '%s' for transfer "
                 "action '%s'", reservation_id, action_id)
-            self._licensing_client.check_reservation(reservation_id)
+            try:
+                transfer_action.reservation_id = (
+                    self._licensing_client.check_refresh_reservation(
+                        reservation_id)['id'])
+            except Exception as ex:
+                exc_code = getattr(ex, 'code', None)
+                if exc_code in [404, 409]:
+                    if exc_code == 409:
+                        LOG.debug(
+                            "Server-side exception occurred while trying to "
+                            "check the existing reservation '%s' for action "
+                            "'%s'. Attempting to create a new reservation. "
+                            "Trace was: %s",
+                            reservation_id, action_id,
+                            utils.get_exception_details())
+                    elif exc_code == 404:
+                        LOG.debug(
+                            "Could not find previous reservation with ID '%s' "
+                            "for action '%s'. Attempting to create a new "
+                            "reservation. Trace was: %s",
+                            reservation_id, action_id,
+                            utils.get_exception_details())
+                    self._check_create_reservation_for_transfer(
+                        transfer_action, reservation_type)
+                else:
+                    raise ex
         else:
             LOG.debug(
-                "Transfer action '%s' has no reservation ID set. Skipping "
-                "all reservation licensing checks.", action_id)
+                "Transfer action '%s' has no reservation ID set.", action_id)
+            self._check_create_reservation_for_transfer(
+                transfer_action, reservation_type)
 
     def create_endpoint(self, ctxt, name, endpoint_type, description,
                         connection_info, mapped_regions=None):
@@ -920,7 +947,8 @@ class ConductorServerEndpoint(object):
     @replica_synchronized
     def execute_replica_tasks(self, ctxt, replica_id, shutdown_instances):
         replica = self._get_replica(ctxt, replica_id)
-        self._check_reservation_for_transfer(replica)
+        self._check_reservation_for_transfer(
+            replica, licensing_client.RESERVATION_TYPE_REPLICA)
         self._check_replica_running_executions(ctxt, replica)
         self._check_minion_pools_for_action(ctxt, replica)
 
@@ -1485,7 +1513,8 @@ class ConductorServerEndpoint(object):
                                  skip_os_morphing=False,
                                  user_scripts=None):
         replica = self._get_replica(ctxt, replica_id)
-        self._check_reservation_for_transfer(replica)
+        self._check_reservation_for_transfer(
+            replica, licensing_client.RESERVATION_TYPE_REPLICA)
         self._check_replica_running_executions(ctxt, replica)
         self._check_valid_replica_tasks_execution(replica, force)
 

+ 58 - 16
coriolis/licensing/client.py

@@ -3,6 +3,7 @@
 
 import json
 import os
+
 import requests
 
 from coriolis import exception
@@ -21,10 +22,11 @@ RESERVATION_TYPE_MIGRATION = "migration"
 class LicensingClient(object):
     """ Class for accessing the Coriolis licensing server API. """
 
-    def __init__(self, base_url, allow_untrusted=False):
+    def __init__(self, base_url, appliance_id=None, allow_untrusted=False):
         """ :param base_url: URL for the API service, including scheme """
         self._base_url = base_url.rstrip('/')
         self._verify = not allow_untrusted
+        self._appliance_id = appliance_id
 
     @classmethod
     def from_env(cls):
@@ -32,6 +34,7 @@ class LicensingClient(object):
         following env vars:
         LICENSING_SERVER_BASE_URL="https://10.7.2.3:37667/v1"
         LICENSING_SERVER_ALLOW_UNTRUSTED="<set to anything>"
+        LICENSING_SERVER_APP_ID_FILE="<path to licensing server ID file>"
         Returns None if 'LICENSING_SERVER_BASE_URL' is not defined.
         """
         base_url = os.environ.get("LICENSING_SERVER_BASE_URL")
@@ -42,9 +45,16 @@ class LicensingClient(object):
             return None
         allow_untrusted = os.environ.get(
             "LICENSING_SERVER_ALLOW_UNTRUSTED", False)
-
-        # try out client:
-        client = cls(base_url, allow_untrusted=allow_untrusted)
+        client = cls(
+            base_url, appliance_id=None, allow_untrusted=allow_untrusted)
+        appliance_ids = client.get_appliances()
+        if not appliance_ids:
+            client._appliance_id = client.create_appliance().get("id")
+        elif len(appliance_ids) == 1:
+            client._appliance_id = appliance_ids[0].get('id')
+        else:
+            raise exception.CoriolisException(
+                'More than one appliance IDs found.')
         client.get_licence_status()
 
         return client
@@ -55,15 +65,22 @@ class LicensingClient(object):
         """
         return "%s/%s" % (self._base_url, resource.strip('/'))
 
+    def _get_url_for_appliance_resource(self, resource):
+        return "%s/appliances/%s/%s" % (
+            self._base_url, self._appliance_id, resource.strip('/'))
+
     @utils.retry_on_error()
     def _do_req(
             self, method_name, resource, body=None,
-            response_key=None, raw_response=False):
+            response_key=None, raw_response=False,
+            appliance_scoped=True):
         method = getattr(requests, method_name.lower(), None)
         if not method:
             raise ValueError("No such HTTP method '%s'" % method_name)
 
         url = self._get_url_for_resource(resource)
+        if appliance_scoped:
+            url = self._get_url_for_appliance_resource(resource)
 
         kwargs = {"verify": self._verify,
                   "timeout": CONF.default_requests_timeout}
@@ -107,24 +124,49 @@ class LicensingClient(object):
 
         return resp_data
 
-    def _get(self, resource, response_key=None):
-        return self._do_req("GET", resource, response_key=response_key)
+    def _get(self, resource, response_key=None, appliance_scoped=True):
+        return self._do_req("GET", resource, response_key=response_key,
+                            appliance_scoped=appliance_scoped)
 
-    def _post(self, resource, body, response_key=None):
+    def _post(self, resource, body, response_key=None, appliance_scoped=True):
         return self._do_req(
-            "POST", resource, body=body, response_key=response_key)
+            "POST", resource, body=body,
+            response_key=response_key,
+            appliance_scoped=appliance_scoped)
 
-    def _put(self, resource, body, response_key=None):
+    def _put(self, resource, body, response_key=None, appliance_scoped=True):
         return self._do_req(
-            "PUT", resource, body=body, response_key=response_key)
+            "PUT", resource, body=body,
+            response_key=response_key,
+            appliance_scoped=appliance_scoped)
 
-    def _delete(self, resource, body, response_key=None):
+    def _delete(self, resource, body, response_key=None, appliance_scoped=True):
         return self._do_req(
-            "DELETE", resource, body=body, response_key=response_key)
+            "DELETE", resource, body=body,
+            response_key=response_key,
+            appliance_scoped=appliance_scoped)
+
+    def get_appliances(self):
+        """ Lists all appliances on the Licensing server. """
+        return self._get(
+            "/appliances",
+            response_key="appliances",
+            appliance_scoped=False)
+
+    def get_appliance(self):
+        """ Get the appliance corresponding to this client instance. """
+        return self._get(
+            "/appliances/%s" % self._appliance_id, response_key="appliance",
+            appliance_scoped=False)
+
+    def create_appliance(self):
+        return self._post(
+            "/appliances", body=None, response_key="appliance",
+            appliance_scoped=False)
 
     def get_licence_status(self):
         """ Gets licence status for appliance. """
-        return self._get("/licence-status", "licence_status")
+        return self._get("/status", "appliance_licence_status")
 
     def get_licences(self):
         """ Lists all installed licences. """
@@ -163,10 +205,10 @@ class LicensingClient(object):
         return self._get(
             "/reservations/%s" % reservation_id, response_key="reservation")
 
-    def check_reservation(self, reservation_id):
+    def check_refresh_reservation(self, reservation_id):
         """ Checks the reservation with the given ID.  """
         return self._post(
-            "/reservations/%s/check" % reservation_id, None,
+            "/reservations/%s/refresh" % reservation_id, None,
             response_key="reservation")
 
     def delete_reservation(self, reservation_id, raise_on_404=False):