grpc-xds/greeter-go/pkg/config/greeter_name.go (57 lines of code) (raw):
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"context"
"errors"
"fmt"
"math/rand"
"os"
"strings"
"time"
"cloud.google.com/go/compute/metadata"
"github.com/go-logr/logr"
"github.com/googlecloudplatform/solutions-workshops/grpc-xds/greeter-go/pkg/logging"
"github.com/googlecloudplatform/solutions-workshops/grpc-xds/greeter-go/pkg/xdsclient/bootstrap"
)
var errNoLocality = errors.New("no locality information in the gRPC xDS bootstrap configuration")
// GreeterName is constructed from the host name and the zone name.
// The zone name is looked up from the.
func GreeterName(ctx context.Context) string {
logger := logging.FromContext(ctx)
zone, err := zoneFromGRPCXDSBootstrapFile()
if err != nil || zone == "" {
zone, err = zoneFromGCPMetadataServer(logger)
if err != nil {
logger.Error(err, "Could not determine the zone from the GCP metadata server")
}
}
return fmt.Sprintf("%s(%s)", hostname(logger), zone)
}
// hostname returns the host name, or a generated name if there is a problem looking up the host name.
/* #nosec G404 -- Weak random number generator is fine here. */
func hostname(logger logr.Logger) string {
hostname, err := os.Hostname()
if err != nil {
logger.Error(err, "Could not determine the host name, using a generated name")
rand.New(rand.NewSource(time.Now().UnixNano()))
return fmt.Sprintf("node-%03d", rand.Int()%100)
}
return hostname
}
// zoneFromGRPCXDSBootstrapFile returns the zone name of the Kubernetes cluster
// node where this Pod is scheduled, by parsing the locality information in
// the gRPC xDS bootstrap file or config.
func zoneFromGRPCXDSBootstrapFile() (string, error) {
bootstrapConfig, err := bootstrap.NewConfigPartial()
if err != nil {
return "", fmt.Errorf("could not parse the gRPC xDS bootstrap configuration: %w", err)
}
if bootstrapConfig.NodeProto.Locality == nil {
return "", errNoLocality
}
return bootstrapConfig.NodeProto.Locality.Zone, nil
}
// zoneFromGCPMetadataServer returns the zone name of the Kubernetes cluster
// node where this Pod is scheduled, by querying the Google Kubernetes Engine
// or Compute Engine
// [metadata server]: https://cloud.google.com/compute/docs/metadata/overview
func zoneFromGCPMetadataServer(logger logr.Logger) (string, error) {
zoneWithProjectNumber, err := metadata.Zone()
if err != nil {
return "", fmt.Errorf("could not look up the zone from the GCP metadata server: %w", err)
}
// zoneWithProjectNumber format is `projects/[PROJECT_NUMBER]/zones/[ZONE]`.
zoneSplit := strings.Split(zoneWithProjectNumber, "/")
if len(zoneSplit) != 4 {
logger.Error(nil, "Unexpected zone format from the GCP metadata server, using it verbatim", "zone", zoneWithProjectNumber)
return zoneWithProjectNumber, nil
}
return zoneSplit[3], nil
}