Azure / Azure-Spring-Apps

Azure Spring Cloud
MIT License
8 stars 5 forks source link

ASA-Enterprise API Portal did not import my APIs #32

Closed ezYakaEagle442 closed 1 year ago

ezYakaEagle442 commented 1 year ago

Describe the bug I have used Bicep which sucessfully provisionned ASA instance with Enterprise Tier + Service Registry + Application configuration service + API Portal + Cloud Gateway + Routing rules below :

[
  {
    "name": "customers-service-gateway-route-config",
    "provisioningState": "Succeeded",
    "routes": [
      {
        "title": "customers-service",
        "description": "customers-service",
        "uri": "http://customers-service",
        "ssoEnabled": false,
        "tokenRelay": false,
        "order": 101
      }
    ],
    "predicates": [
      "/api/customer/**"
    ],
    "filters": [
      "StripPrefix=0",
      "RateLimit=2,5s"
    ],
    "appName": "customers-service",
    "protocol": "HTTP"
  },
  {
    "name": "vets-service-gateway-route-config",
    "provisioningState": "Succeeded",
    "routes": [
      {
        "title": "vets-service",
        "description": "vets-service",
        "uri": "http://vets-service",
        "ssoEnabled": false,
        "tokenRelay": false,
        "order": 102
      }
    ],
    "predicates": [
      "/api/vet/**",
      "RateLimit=2,5s"
    ],
    "filters": [
      "StripPrefix=0"
    ],
    "appName": "vets-service",
    "protocol": "HTTP"
  },
  {
    "name": "visits-service-gateway-route-config",
    "provisioningState": "Succeeded",
    "routes": [
      {
        "title": "visits-service",
        "description": "visits-service",
        "uri": "http://visits-service",
        "ssoEnabled": false,
        "tokenRelay": false,
        "order": 103
      }
    ],
    "predicates": [
      "/api/visit/**"
    ],
    "filters": [
      "StripPrefix=0",
      "RateLimit=2,5s"
    ],
    "appName": "visits-service",
    "protocol": "HTTP"
  }
]

To Reproduce run my repo : https://github.com/ezYakaEagle442/azure-spring-apps-petclinic-mic-srv/

Expected behavior All the 3 API should be sucessfully imported

Screenshots see below

image

Additional context

leonard520 commented 1 year ago

@ezYakaEagle442 Are you using the correct route config? From my understanding, the StripPrefix should be 2 in the case.

ezYakaEagle442 commented 1 year ago

@leonard520 I have redeployed ASA-E with latest BIcep API, chnaged to 'StripPrefix=2' but the API does still not show up correctly in the Portal


// https://learn.microsoft.com/en-us/azure/templates/microsoft.appplatform/2022-11-01-preview/spring/gateways/routeconfigs?pivots=deployment-language-bicep
resource VetsGatewayRouteConfig 'Microsoft.AppPlatform/Spring/gateways/routeConfigs@2022-12-01' = if (azureSpringAppsTier=='Enterprise') {
  name: 'vets-service-gateway-route-config'
  parent: gateway
  properties: {
    appResourceId: vetsserviceapp.id
    protocol: 'HTTP'
    routes: [
      {
        title: 'vets-service'
        description: 'vets-service'
        uri: 'http://vets-service'
        order: 102
        ssoEnabled: apiPortalSsoEnabled
        filters: [
          'StripPrefix=2' // https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-stripprefix-gatewayfilter-factory
        ]
        predicates: [
          '/api/vet/**'
          'RateLimit=2,5s' // limit all users to two requests every 5 seconds
        ]        
      }
    ]
  }
}
output VetsGatewayRouteConfigId string = VetsGatewayRouteConfig.id
output VetsGatewayRouteConfigAppResourceId string = VetsGatewayRouteConfig.properties.appResourceId
output VetsGatewayRouteConfigRoutes array = VetsGatewayRouteConfig.properties.routes
output VetsGatewayRouteConfigIsSsoEnabled bool = VetsGatewayRouteConfig.properties.routes[0].ssoEnabled
output VetsGatewayRouteConfigPredicates array = VetsGatewayRouteConfig.properties.routes[0].predicates

resource VisitsGatewayRouteConfig 'Microsoft.AppPlatform/Spring/gateways/routeConfigs@2022-12-01' = if (azureSpringAppsTier=='Enterprise') {
  name: 'visits-service-gateway-route-config'
  parent: gateway
  properties: {
    appResourceId: visitsservicerapp.id
    protocol: 'HTTP'
    routes: [
      {
        title: 'visits-service' 
        description: 'visits-service'
        uri: 'http://visits-service'
        order: 103
        ssoEnabled: apiPortalSsoEnabled
        filters: [
          'StripPrefix=2' // https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-stripprefix-gatewayfilter-factory
        ]
        predicates: [
          '/api/visit/**'
          'RateLimit=2,5s' // limit all users to two requests every 5 seconds
        ]  
      }
    ]
  }
}
output VisitsGatewayRouteConfigId string = VisitsGatewayRouteConfig.id
output VisitsGatewayRouteConfigAppResourceId string = VisitsGatewayRouteConfig.properties.appResourceId
output VisitsGatewayRouteConfigRoutes array = VisitsGatewayRouteConfig.properties.routes
output VisitsGatewayRouteConfigIsSsoEnabled bool = VisitsGatewayRouteConfig.properties.routes[0].ssoEnabled
output VisitsGatewayRouteConfigPredicates array = VisitsGatewayRouteConfig.properties.routes[0].predicates

resource CustomersGatewayRouteConfig 'Microsoft.AppPlatform/Spring/gateways/routeConfigs@2022-12-01' = if (azureSpringAppsTier=='Enterprise') {
  name: 'customers-service-gateway-route-config'
  parent: gateway
  properties: {
    appResourceId: customersserviceapp.id
    protocol: 'HTTP'
    routes: [
      {
        description: 'customers-service'
        title: 'customers-service'
        uri: 'http://customers-service'
        order: 101
        ssoEnabled: apiPortalSsoEnabled
        filters: [
          'StripPrefix=2' // https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-stripprefix-gatewayfilter-factory
          'RateLimit=2,5s' // limit all users to two requests every 5 seconds
        ]
        predicates: [
          '/api/customer/**'
        ]
      }
    ]
  }
}
output CustomersGatewayRouteConfigId string = CustomersGatewayRouteConfig.id
output CustomersGatewayRouteConfigAppResourceId string = CustomersGatewayRouteConfig.properties.appResourceId
output CustomersGatewayRouteConfigRoutes array = CustomersGatewayRouteConfig.properties.routes
output CustomersGatewayRouteConfigIsSsoEnabled bool = CustomersGatewayRouteConfig.properties.routes[0].ssoEnabled
output CustomersGatewayRouteConfigPredicates array = CustomersGatewayRouteConfig.properties.routes[0].predicates
ezYakaEagle442 commented 1 year ago

thank you @leonard520

this is now fixed with the correct syntax :


resource apiPortal 'Microsoft.AppPlatform/Spring/apiPortals@2022-12-01' = if (azureSpringAppsTier=='Enterprise') {
  name: apiPortalName
  parent: azureSpringApps
  sku: {
    name: azureSpringAppsSkuName
    capacity: any(1) // Number of instance
    tier: azureSpringAppsTier
  }
  properties: {
    gatewayIds: [
        //'${azureSpringApps.id}/gateways/${gatewayName}'
        gateway.id
      ]
    httpsOnly: false
    public: true
    ssoProperties: {
      clientId: apiPortalSsoClientId
      clientSecret: apiPortalSsoClientSecret
      issuerUri: apiPortalSsoIssuerUri
      scope: [
        'openid'
        'profile'
        'email'
      ]
    }
  }
  dependsOn:  [
    gateway
  ]
}
output apiPortalId string = apiPortal.id
output apiPortalUrl string = apiPortal.properties.url
output gatewayIds array = apiPortal.properties.gatewayIds

// https://learn.microsoft.com/en-us/azure/templates/microsoft.appplatform/2022-11-01-preview/spring/gateways?pivots=deployment-language-bicep
resource gateway 'Microsoft.AppPlatform/Spring/gateways@2022-12-01' = if (azureSpringAppsTier=='Enterprise') {
  name: gatewayName
  parent: azureSpringApps
  sku: {
    name: azureSpringAppsSkuName
    capacity: any(1)
    tier: azureSpringAppsTier
  }
  properties: {
    httpsOnly: false // for custom domain ONLY ?
    public: true
    // az spring gateway update --help
    resourceRequests: {
      cpu: '1' // CPU resource quantity. Should be 500m or number of CPU cores.
      memory: '1Gi' // Memory resource quantity. Should be 512Mi or #Gi, e.g., 1Gi, 3Gi.
    }
    ssoProperties: {
      clientId: apiPortalSsoClientId
      clientSecret: apiPortalSsoClientSecret
      issuerUri: apiPortalSsoIssuerUri
      scope: [
        'openid'
        'profile'
        'email'
      ]
    }
    apiMetadataProperties: {
      title: 'Spring Cloud Gateway for Petclinic' // Title describing the context of the APIs available on the Gateway instance (default: Spring Cloud Gateway for K8S)
      description: '' // description of the APIs available on the Gateway instance (default: Generated OpenAPI 3 document that describes the API routes configured for '[Gateway instance name]' Spring Cloud Gateway instance deployed under '[namespace]' namespace.)
      version: '1.0.0' // Version of APIs available on this Gateway instance (default: unspecified)
      serverUrl: gatewayServerUrl // ex: https://asae-petcliasa-gateway-424242.svc.azuremicroservices.io/ ==> Base URL that API consumers will use to access APIs on the Gateway instance.
      documentation: '' // Location of additional documentation for the APIs available on the Gateway instance
    }
    /* Spring Cloud Gateway APM feature is not enabled
    apmTypes: [
      'ApplicationInsights'
    ]
    */
    corsProperties: {
      allowCredentials: false
      allowedOrigins: [
        '*'
      ]
      allowedMethods: [
        'GET'
        'POST'
        'PUT'
        'DELETE'
      ]
      allowedHeaders: [
        '*'
      ]
    }
  }
}
output gatewayId string = gateway.id
output gatewayUrl string = gateway.properties.url

resource vetsserviceapp 'Microsoft.AppPlatform/Spring/apps@2022-12-01' existing = {
  name: 'vets-service'
  parent: azureSpringApps
}

resource customersserviceapp 'Microsoft.AppPlatform/Spring/apps@2022-12-01' existing = {
  name: 'customers-service'
  parent: azureSpringApps
}

resource visitsservicerapp 'Microsoft.AppPlatform/Spring/apps@2022-12-01' existing = {
  name: 'visits-service'
  parent: azureSpringApps
}

// https://learn.microsoft.com/en-us/azure/templates/microsoft.appplatform/2022-11-01-preview/spring/gateways/routeconfigs?pivots=deployment-language-bicep
resource VetsGatewayRouteConfig 'Microsoft.AppPlatform/Spring/gateways/routeConfigs@2022-12-01' = if (azureSpringAppsTier=='Enterprise') {
  name: 'vets-service-gateway-route-config'
  parent: gateway
  properties: {
    appResourceId: vetsserviceapp.id
    protocol: 'HTTP'
    routes: [
      {
        title: 'Get All Vets'
        description: 'Get All Vets calling vets-service'
        order: 120
        filters: [
          'StripPrefix=2' // https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-stripprefix-gatewayfilter-factory
          'RateLimit=2,5s' // limit all users to two requests every 5 seconds https://learn.microsoft.com/en-us/azure/spring-apps/quickstart-set-request-rate-limits-enterprise
        ]
        predicates: [
          // 'Path=/api/vet/**'
          'Path=/api/vet/vets'
        ]        
      }
    ]
  }
}
output VetsGatewayRouteConfigId string = VetsGatewayRouteConfig.id
output VetsGatewayRouteConfigAppResourceId string = VetsGatewayRouteConfig.properties.appResourceId
output VetsGatewayRouteConfigRoutes array = VetsGatewayRouteConfig.properties.routes
output VetsGatewayRouteConfigIsSsoEnabled bool = VetsGatewayRouteConfig.properties.routes[0].ssoEnabled
output VetsGatewayRouteConfigPredicates array = VetsGatewayRouteConfig.properties.routes[0].predicates

resource VisitsGatewayRouteConfig 'Microsoft.AppPlatform/Spring/gateways/routeConfigs@2022-12-01' = if (azureSpringAppsTier=='Enterprise') {
  name: 'visits-service-gateway-route-config'
  parent: gateway
  properties: {
    appResourceId: visitsservicerapp.id
    protocol: 'HTTP'
    routes: [
      {
        title: 'Get Visits for a given {ownerId} & /{petId}' 
        description: 'Get Visits calling visits-service'
        order: 110
        filters: [
          'StripPrefix=2' // https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-stripprefix-gatewayfilter-factory
          'RateLimit=2,5s' // limit all users to two requests every 5 seconds https://docs.vmware.com/en/VMware-Spring-Cloud-Gateway-for-Kubernetes/1.2/scg-k8s/GUID-route-filters.html#ratelimit-limiting-user-requests-filter
        ]
        predicates: [
          // 'Path=/api/visit/**'
          'Path=/api/visit/owners/{ownerId}/pets/{petId}/visits'
        ]  
      }
    ]
  }
}
output VisitsGatewayRouteConfigId string = VisitsGatewayRouteConfig.id
output VisitsGatewayRouteConfigAppResourceId string = VisitsGatewayRouteConfig.properties.appResourceId
output VisitsGatewayRouteConfigRoutes array = VisitsGatewayRouteConfig.properties.routes
output VisitsGatewayRouteConfigIsSsoEnabled bool = VisitsGatewayRouteConfig.properties.routes[0].ssoEnabled
output VisitsGatewayRouteConfigPredicates array = VisitsGatewayRouteConfig.properties.routes[0].predicates

resource CustomersGatewayRouteConfig 'Microsoft.AppPlatform/Spring/gateways/routeConfigs@2022-12-01' = if (azureSpringAppsTier=='Enterprise') {
  name: 'customers-service-gateway-route-config'
  parent: gateway
  properties: {
    appResourceId: customersserviceapp.id
    protocol: 'HTTP'
    routes: [
      {
        description: 'Get owners customers-service'
        title: 'Get owners'
        //uri: URI field should be used only ro route to external service out of ASA
        order: 101
        // ssoEnabled: false
        filters: [
          'StripPrefix=2' // https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-stripprefix-gatewayfilter-factory
          'RateLimit=2,5s' // limit all users to two requests every 5 seconds https://docs.vmware.com/en/VMware-Spring-Cloud-Gateway-for-Kubernetes/1.2/scg-k8s/GUID-route-filters.html#ratelimit-limiting-user-requests-filter
        ]
        predicates: [ // /!\ 1 Path ONLY inside predicates
          // 'Path=/api/customer/**' // https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-path-route-predicate-factory
          'Path=/api/customer/owners'
        ]
      }
      {
        description: 'Get Pet Types'
        title: 'Get Pet Types calling customers-service'
        order: 102
        // ssoEnabled: false
        filters: [
          'StripPrefix=2' // https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-stripprefix-gatewayfilter-factory
          'RateLimit=2,5s' // limit all users to two requests every 5 seconds https://docs.vmware.com/en/VMware-Spring-Cloud-Gateway-for-Kubernetes/1.2/scg-k8s/GUID-route-filters.html#ratelimit-limiting-user-requests-filter
        ]
        predicates: [
          // 'Path=/api/customer/**' // https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-path-route-predicate-factory
          'Path=/api/customer/petTypes'
        ]
      }
      {
        description: 'Get Owner given a {ownerId}'
        title: 'Get Owner calling customers-service'
        order: 103
        // ssoEnabled: false
        filters: [
          'StripPrefix=2' // https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-stripprefix-gatewayfilter-factory
          'RateLimit=2,5s' // limit all users to two requests every 5 seconds https://docs.vmware.com/en/VMware-Spring-Cloud-Gateway-for-Kubernetes/1.2/scg-k8s/GUID-route-filters.html#ratelimit-limiting-user-requests-filter
        ]
        predicates: [
          // 'Path=/api/customer/**' // https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-path-route-predicate-factory
          'Path=/api/customer/owners/{ownerId}'
        ]
      }      
      {
        description: 'Get a Pet given a {ownerId} and a {petId}'
        title: 'Get Pet calling customers-service'
        order: 105
        // ssoEnabled: false
        filters: [
          'StripPrefix=2' // https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-stripprefix-gatewayfilter-factory
          'RateLimit=2,5s' // limit all users to two requests every 5 seconds https://docs.vmware.com/en/VMware-Spring-Cloud-Gateway-for-Kubernetes/1.2/scg-k8s/GUID-route-filters.html#ratelimit-limiting-user-requests-filter
        ]
        predicates: [
          // 'Path=/api/customer/**' // https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-path-route-predicate-factory
          'Path=/api/customer/owners/{ownerId}/pets/{petId}'
        ]
      } 
    ]
  }
}
output CustomersGatewayRouteConfigId string = CustomersGatewayRouteConfig.id
output CustomersGatewayRouteConfigAppResourceId string = CustomersGatewayRouteConfig.properties.appResourceId
output CustomersGatewayRouteConfigRoutes array = CustomersGatewayRouteConfig.properties.routes
output CustomersGatewayRouteConfigRoute0Predicates array = CustomersGatewayRouteConfig.properties.routes[0].predicates
ezYakaEagle442 commented 1 year ago

what about Spring Cloud Gateway APM feature : is it enabled now ? apmTypes: [ 'ApplicationInsights' ]

leonard520 commented 1 year ago

As offline discussed, the filter should be fixed and API portal is able to import APIs now. If you have other question, feel free to raise other issues to us.