Uploaded image for project: 'Libcloud'
  1. Libcloud
  2. LIBCLOUD-878

GCP - Not able to retrieve the Load Balancer info when having a VPN setup on project.

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Open
    • Minor
    • Resolution: Unresolved
    • None
    • None
    • LoadBalancer
    • None
    • GCP

    Description

      I was trying to retrieve the LB info from my GCP project when I get the following error :

      Traceback (most recent call last):
      File "LbTestPy.py", line 41, in <module>
      aLbs = lb_driver.list_balancers(ex_region="us-east1")
      File "/home/cloud-user/LbTest/src/apache-libcloud/libcloud/loadbalancer/drivers/gce.py", line 87, in list_balancers
      for fwr in self.gce.ex_list_forwarding_rules(region=ex_region):
      File "/home/cloud-user/LbTest/src/apache-libcloud/libcloud/compute/drivers/gce.py", line 2092, in ex_list_forwarding_rules
      for f in response['items']]
      File "/home/cloud-user/LbTest/src/apache-libcloud/libcloud/compute/drivers/gce.py", line 7893, in _to_forwarding_rule
      target = self._get_object_by_kind(forwarding_rule['target'])
      File "/home/cloud-user/LbTest/src/apache-libcloud/libcloud/compute/drivers/gce.py", line 7249, in _get_object_by_kind
      return GCENodeDriver.KIND_METHOD_MAP[response['kind']](self, response)
      KeyError: 'compute#targetVpnGateway'

      First I think it was my code/config but my test case is pretty simple (and I also lost the VM before the LB without issue).
      After some investigation I manage to find the issue in libcloud/google.

      The issue is that libcloud will list the forwarding rules to retrieve the info of the LoadBalancer. It retrieve the following forwarding rules :
      https://cloud.google.com/compute/docs/load-balancing/network/forwarding-rules

      In my case here is an extract of the HTTP response (retrieve by setting debug mode of libcloud):

      1. -------- begin 43335184 request ----------
        curl -i -X GET -H 'Host: www.googleapis.com' -H 'Accept-Encoding: gzip,deflate' -H 'X-LC-Request-ID: 43335184' -H 'Content-Type: application/json' -H 'Authorization: Bearer ya29.El6eXXXXOc2Kn' -H 'User-Agent: libcloud/1.4.0 (Google Compute Engine) (Python 2.7.5/linux2)' --compress https://www.googleapis.com:443/compute/v1/projects/XXXXX/regions/us-east1/forwardingRules
      2. -------- begin 43335184:43218488 response ----------
        HTTP/1.1 200 OK
        X-Xss-Protection: 1; mode=block
        X-Content-Type-Options: nosniff
        Content-Encoding: gzip
        Transfer-Encoding: chunked
        Expires: Tue, 22 Nov 2016 13:15:18 GMT
        Vary: Origin, X-Origin
        Server: GSE
        Etag: "OKaT3lMknXXXXCJyDlI"
        Cache-Control: private, max-age=0, must-revalidate, no-transform
        Date: Tue, 22 Nov 2016 13:15:18 GMT
        X-Frame-Options: SAMEORIGIN
        Alt-Svc: quic=":443"; ma=2592000; v="36,35,34"
        Content-Type: application/json; charset=UTF-8

      444b
      {
      "kind": "compute#forwardingRuleList",
      "id": "projects/XXXXX/regions/us-east1/forwardingRules",
      "items": [

      { "kind": "compute#forwardingRule", "id": "575XXXXXXXXXX282", "creationTimestamp": "2016-07-11T01:31:17.574-07:00", "name": "esp-acsgopstrain-a-us-east1", "description": "", "region": "https://www.googleapis.com/compute/v1/projects/XXXXX/regions/us-east1", "IPAddress": "XXXXXXXXXX", "IPProtocol": "ESP", "target": "https://www.googleapis.com/compute/v1/projects/XXXXX/regions/us-east1/targetVpnGateways/acsgopstrain-a-us-east1", "selfLink": "https://www.googleapis.com/compute/v1/projects/XXXXX/regions/us-east1/forwardingRules/esp-acsgopstrain-a-us-east1", "loadBalancingScheme": "EXTERNAL" }

      ,
      ...

      { "kind": "compute#forwardingRule", "id": "6429XXXXXXXXXX887", "creationTimestamp": "2016-11-21T09:46:32.011-08:00", "name": "us-lb-forwarding-rule", "description": "", "region": "https://www.googleapis.com/compute/v1/projects/XXXXX/regions/us-east1", "IPAddress": "1XXXXXXXXXX5", "IPProtocol": "TCP", "portRange": "30012-30012", "target": "https://www.googleapis.com/compute/v1/projects/XXXXX/regions/us-east1/targetPools/us-lb", "selfLink": "https://www.googleapis.com/compute/v1/projects/XXXXX/regions/us-east1/forwardingRules/us-lb-forwarding-rule", "loadBalancingScheme": "EXTERNAL" }

      ],
      "selfLink": "https://www.googleapis.com/compute/v1/projects/XXXXX/regions/us-east1/forwardingRules"
      }

      The first thing that surprise me is that the response was big even if i have only 1 load balancer on this region. After it receive this response libcloud will try to convert each "forwading rule" from the message to a libcloud object with :

      code1.py
      if 'items' in response:
            # The aggregated result returns dictionaries for each region
            if not global_rules and region is None:
                for v in response['items'].values():
                    region_forwarding_rules = [
                        self._to_forwarding_rule(f)
                        for f in v.get('forwardingRules', [])
                    ]
                    list_forwarding_rules.extend(region_forwarding_rules)
            else:
                list_forwarding_rules = [self._to_forwarding_rule(f)
                                         for f in response['items']]
        return list_forwarding_rules
      

      from def ex_list_forwarding_rules(self, region=None, global_rules=False):

      To do so libcloud will call the following method "_to_forwarding_rule" on all items. This is where it break !
      Indeed if you look on the answer of the "list forwardingRules" you will see that I have 2 types of rules :

      Type 1 : The forward rules from the load balancer object :

      {
      "kind": "compute#forwardingRule",
      "id": "6429XXXXXXXXXX887",
      "creationTimestamp": "2016-11-21T09:46:32.011-08:00",
      "name": "us-lb-forwarding-rule",
      "description": "",
      "region": "https://www.googleapis.com/compute/v1/projects/XXXXX/regions/us-east1",
      "IPAddress": "1XXXXXXXXXX5",
      "IPProtocol": "TCP",
      "portRange": "30012-30012",
      "target": "https://www.googleapis.com/compute/v1/projects/XXXXX/regions/us-east1/targetPools/us-lb",
      "selfLink": "https://www.googleapis.com/compute/v1/projects/XXXXX/regions/us-east1/forwardingRules/us-lb-forwarding-rule",
      "loadBalancingScheme": "EXTERNAL"
      }

      Type 2 : Forward rules from the VPN I have between projects on GCP

      {
      "kind": "compute#forwardingRule",
      "id": "575XXXXXXXXXX282",
      "creationTimestamp": "2016-07-11T01:31:17.574-07:00",
      "name": "esp-acsgopstrain-a-us-east1",
      "description": "",
      "region": "https://www.googleapis.com/compute/v1/projects/XXXXX/regions/us-east1",
      "IPAddress": "XXXXXXXXXX",
      "IPProtocol": "ESP",
      "target": "https://www.googleapis.com/compute/v1/projects/XXXXX/regions/us-east1/targetVpnGateways/acsgopstrain-a-us-east1",
      "selfLink": "https://www.googleapis.com/compute/v1/projects/XXXXX/regions/us-east1/forwardingRules/esp-acsgopstrain-a-us-east1",
      "loadBalancingScheme": "EXTERNAL"
      },

      The libcloud method "_to_forwarding_rule" will works fine on the type 1. Here is the code :

      code2.py
      def _to_forwarding_rule(self, forwarding_rule):
          """
          Return a Forwarding Rule object from the JSON-response dictionary.
          :param  forwarding_rule: The dictionary describing the rule.
          :type   forwarding_rule: ``dict``
          :return: ForwardingRule object
          :rtype: :class:`GCEForwardingRule`
          """
          extra = {}
          extra['selfLink'] = forwarding_rule.get('selfLink')
          extra['portRange'] = forwarding_rule.get('portRange')
          extra['creationTimestamp'] = forwarding_rule.get('creationTimestamp')
          extra['description'] = forwarding_rule.get('description')
      
      
          region = forwarding_rule.get('region')
          if region:
              region = self.ex_get_region(region)
          target = self._get_object_by_kind(forwarding_rule['target'])
      

      The "_get_object_by_kind" will works fine because the target of the forward rule for type 1 is "targetpool" as you can see :
      "https://www.googleapis.com/compute/v1/projects/XXXXX/regions/us-east1/targetPools/us-lb",

      whereas it will crash with the stack i show you before for the type 2 because the target is "targetVpnGateways" as you can see :
      "https://www.googleapis.com/compute/v1/projects/XXXXX/regions/us-east1/targetVpnGateways/acsgopstrain-a-us-east1",

      I think the original implementation of the LB on libcloud for GCE did not know that Google will mix several rules for both the LoadBalancer AND the VPN.

      I made a dirty fix on my libcloud master code to only try to convert the forward rules link to a LB :

      code3.py
      	else:
      		list_forwarding_rules = [self._to_forwarding_rule(f)
      			for f in response['items'] if (not "targetVpnGateways" in f['target'])]
      

      This fix the issue !

      To be honest I m not sure what to do....I would except Google to not mix the forward rules of VPN and LB. There is nothing mentioning the VPN in the forwarding rules in the google doc (https://cloud.google.com/compute/docs/load-balancing/network/forwarding-rules) and there is nothing about forwarding rule in the VPN documentation (https://cloud.google.com/compute/docs/vpn/networks)

      I would suggest to do a temporary hack (similar in spirit of the one i done) until we clarify that with Google.

      Attachments

        Activity

          People

            Unassigned Unassigned
            charly37 charles walker
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated: