# Vert.x Service Resolver

The Service Resolver library is a plugin that lets Vert.x clients call services using logical service names instead of network addresses. The service resolver is also able to perform client side load balancing with the usual strategies.

You can use a service resolver as a client to query a resolver or integrated natively with a Vert.x client.

## Service resolver client

You can query a service resolver with the service resolver client.

    ServiceResolverClient client = ServiceResolverClient.create(vertx, new KubeResolverOptions());

    // Resolve a service endpoint
    Future<Endpoint> fut = client.resolveEndpoint(ServiceAddress.of("the-service"));

    fut.onSuccess(endpoint -> {

      // Print physical servers details
      List<ServerEndpoint> servers = endpoint.servers();
      for (ServerEndpoint server : servers) {
        System.out.println("Available server: " + server.address());
      }
    });

You can also let the load balancer select nodes

    ServiceResolverClient client = ServiceResolverClient.create(vertx, new KubeResolverOptions());

    // Resolve a service endpoint
    Future<Endpoint> fut = client.resolveEndpoint(ServiceAddress.of("the-service"));

    fut.onSuccess(endpoint -> {

      // Print physical servers details
      List<ServerEndpoint> servers = endpoint.servers();
      for (ServerEndpoint server : servers) {
        System.out.println("Available server: " + server.address());
      }
    });

## Client integration

The service resolver is integrated with the Vert.x HTTP and Web clients.

### Getting started with the Vert.x HTTP Client

Given a resolver, you can configure a Vert.x HTTP Client to use it thanks to an `HttpClientBuilder`.

    HttpClient client = vertx.httpClientBuilder()
      .withAddressResolver(resolver)
      .build();

A service is addressed with a `ServiceAddress` instead of a `SocketAddress`.

    ServiceAddress serviceAddress = ServiceAddress.of("the-service");

    Future<HttpClientRequest> requestFuture = client.request(new RequestOptions()
      .setMethod(HttpMethod.GET)
      .setURI("/")
      .setServer(serviceAddress));

    Future<Buffer> resultFuture = requestFuture.compose(request -> request
      .send()
      .compose(response -> {
        if (response.statusCode() == 200) {
          return response.body();
        } else {
          return Future.failedFuture("Invalid status response:" + response.statusCode());
        }
      }));

### Getting started with the Vert.x Web Client

Given a resolver, you can configure a Vert.x Web Client to use it thanks to an `HttpClientBuilder`.

    HttpClient httpClient = vertx.httpClientBuilder()
      .withAddressResolver(resolver)
      .build();
    WebClient webClient = WebClient.wrap(httpClient);

A service is addressed with a `ServiceAddress`.

    ServiceAddress serviceAddress = ServiceAddress.create("the-service");

    Future<HttpResponse<Buffer>> future = webClient
      .request(HttpMethod.GET, new RequestOptions().setServer(serviceAddress))
      .send();

### Client side load balancing

The default load balancing behavior is round-robin, you can change the load balancer to use:

    HttpClient client = vertx.httpClientBuilder()
      .withAddressResolver(resolver)
      .withLoadBalancer(LoadBalancer.LEAST_REQUESTS)
      .build();

## Service resolver implementations

The service resolver integrates with a few discovery services such as Kubernetes and DNS SRV records.

### Kubernetes resolver

The Kubernetes resolver locates services within a Kubernetes cluster.

| The Kubernetes resolver requires the `endpoints` resource to be accessible using the service account configured for the pod. Here is an example configuration of role and role binding for the `default` service account:
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: observe-endpoints
      namespace: default
    rules:
      - apiGroups: [""]
        resources: ["endpoints"]
        verbs: ["get", "watch", "list"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: observe-endpoints
      namespace: default
    roleRef:
      kind: Role
      name: observe-endpoints
      apiGroup: rbac.authorization.k8s.io
    subjects:
      - kind: ServiceAccount
        name: default
        namespace: default

    KubeResolverOptions options = new KubeResolverOptions();

    AddressResolver resolver = KubeResolver.create(options);

    HttpClient client = vertx.httpClientBuilder()
      .withAddressResolver(resolver)
      .build();

The default resolver options values are loaded from the pod environment - `KUBERNETES_SERVICE_HOST` - `KUBERNETES_SERVICE_PORT` - `/var/run/secrets/kubernetes.io/serviceaccount/token` - `/var/run/secrets/kubernetes.io/serviceaccount/ca.crt` - `/var/run/secrets/kubernetes.io/serviceaccount/namespace`

You can override these settings.

    KubeResolverOptions options = new KubeResolverOptions()
      .setServer(SocketAddress.inetSocketAddress(port, host))
      .setNamespace(namespace)
      .setBearerToken(bearerToken)
      .setHttpClientOptions(httpClientOptions)
      .setWebSocketClientOptions(wsClientOptions);

### SRV resolver

The SRV resolver uses DNS SRV records to resolve and locate services.

    SrvResolverOptions options = new SrvResolverOptions()
      .setServer(SocketAddress.inetSocketAddress(dnsPort, dnsServer));

    AddressResolver resolver = SrvResolver.create(options);

    HttpClient client = vertx.httpClientBuilder()
      .withAddressResolver(resolver)
      .build();