func (g *Cloud) ListInstanceNames(project, zone string) (string, error) {
	ctx, cancel := cloud.ContextWithCallTimeout()
	defer cancel()
	l, err := g.c.Instances().List(ctx, zone, filter.None)
	if err != nil {
		return "", err
	}
	var names []string
	for _, i := range l {
		names = append(names, i.Name)
	}
	return strings.Join(names, " "), nil
}
ListInstanceNames returns a string of instance names separated by spaces.
This method should only be used for e2e testing.
TODO: remove this method.
package gce
import (
	"context"
	"fmt"
	"net"
	"net/http"
	"strings"
	"time"
	"cloud.google.com/go/compute/metadata"
	computebeta "google.golang.org/api/compute/v0.beta"
	compute "google.golang.org/api/compute/v1"
	"k8s.io/klog/v2"
	"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud"
	"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud/filter"
	"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud/meta"
	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/apimachinery/pkg/util/wait"
	cloudprovider "k8s.io/cloud-provider"
)
const (
	defaultZone                   = ""
	networkInterfaceIP            = "instance/network-interfaces/%s/ip"
	networkInterfaceAccessConfigs = "instance/network-interfaces/%s/access-configs"
	networkInterfaceExternalIP    = "instance/network-interfaces/%s/access-configs/%s/external-ip"
)
func newInstancesMetricContext(request, zone string) *metricContext {
	return newGenericMetricContext("instances", request, unusedMetricLabel, zone, computeV1Version)
}
func splitNodesByZone(nodes []*v1.Node) map[string][]*v1.Node {
	zones := make(map[string][]*v1.Node)
	for _, n := range nodes {
		z := getZone(n)
		if z != defaultZone {
			zones[z] = append(zones[z], n)
		}
	}
	return zones
}
func getZone(n *v1.Node) string {
	zone, ok := n.Labels[v1.LabelFailureDomainBetaZone]
	if !ok {
		return defaultZone
	}
	return zone
}
func makeHostURL(projectsAPIEndpoint, projectID, zone, host string) string {
	host = canonicalizeInstanceName(host)
	return projectsAPIEndpoint + strings.Join([]string{projectID, "zones", zone, "instances", host}, "/")
}
func (g *Cloud) ToInstanceReferences(zone string, instanceNames []string) (refs []*compute.InstanceReference) {
	for _, ins := range instanceNames {
		instanceLink := makeHostURL(g.projectsBasePath, g.projectID, zone, ins)
		refs = append(refs, &compute.InstanceReference{Instance: instanceLink})
	}
	return refs
}
func (g *Cloud) NodeAddresses(ctx context.Context, nodeName types.NodeName) ([]v1.NodeAddress, error) {
	timeoutCtx, cancel := context.WithTimeout(ctx, 1*time.Hour)
	defer cancel()
	instanceName := string(nodeName)
	if g.useMetadataServer {
		if g.isCurrentInstance(instanceName) {
			nics, err := metadata.Get("instance/network-interfaces/")
			if err != nil {
				return nil, fmt.Errorf("couldn't get network interfaces: %v", err)
			}
			nicsArr := strings.Split(nics, "/\n")
			nodeAddresses := []v1.NodeAddress{}
			for _, nic := range nicsArr {
				if nic == "" {
					continue
				}
				internalIP, err := metadata.Get(fmt.Sprintf(networkInterfaceIP, nic))
				if err != nil {
					return nil, fmt.Errorf("couldn't get internal IP: %v", err)
				}
				nodeAddresses = append(nodeAddresses, v1.NodeAddress{Type: v1.NodeInternalIP, Address: internalIP})
				acs, err := metadata.Get(fmt.Sprintf(networkInterfaceAccessConfigs, nic))
				if err != nil {
					return nil, fmt.Errorf("couldn't get access configs: %v", err)
				}
				acsArr := strings.Split(acs, "/\n")
				for _, ac := range acsArr {
					if ac == "" {
						continue
					}
					externalIP, err := metadata.Get(fmt.Sprintf(networkInterfaceExternalIP, nic, ac))
					if err != nil {
						return nil, fmt.Errorf("couldn't get external IP: %v", err)
					}
					if externalIP != "" {
						nodeAddresses = append(nodeAddresses, v1.NodeAddress{Type: v1.NodeExternalIP, Address: externalIP})
					}
				}
			}
			internalDNSFull, err := metadata.Get("instance/hostname")
			if err != nil {
				klog.Warningf("couldn't get full internal DNS name: %v", err)
			} else {
				nodeAddresses = append(nodeAddresses,
					v1.NodeAddress{Type: v1.NodeInternalDNS, Address: internalDNSFull},
					v1.NodeAddress{Type: v1.NodeHostName, Address: internalDNSFull},
				)
			}
			return nodeAddresses, nil
		}
	}
	instanceObj, err := g.getInstanceByName(instanceName)
	if err != nil {
		return nil, fmt.Errorf("couldn't get instance details: %v", err)
	}
	instance, err := g.c.Instances().Get(timeoutCtx, meta.ZonalKey(canonicalizeInstanceName(instanceObj.Name), instanceObj.Zone))
	if err != nil {
		return []v1.NodeAddress{}, fmt.Errorf("error while querying for instance: %v", err)
	}
	return nodeAddressesFromInstance(instance)
}
func (g *Cloud) NodeAddressesByProviderID(ctx context.Context, providerID string) ([]v1.NodeAddress, error) {
	timeoutCtx, cancel := context.WithTimeout(ctx, 1*time.Hour)
	defer cancel()
	_, zone, name, err := splitProviderID(providerID)
	if err != nil {
		return []v1.NodeAddress{}, err
	}
	instance, err := g.c.Instances().Get(timeoutCtx, meta.ZonalKey(canonicalizeInstanceName(name), zone))
	if err != nil {
		return []v1.NodeAddress{}, fmt.Errorf("error while querying for providerID %q: %v", providerID, err)
	}
	return nodeAddressesFromInstance(instance)
}
func (g *Cloud) instanceByProviderID(providerID string) (*gceInstance, error) {
	project, zone, name, err := splitProviderID(providerID)
	if err != nil {
		return nil, err
	}
	instance, err := g.getInstanceFromProjectInZoneByName(project, zone, name)
	if err != nil {
		if isHTTPErrorCode(err, http.StatusNotFound) {
			return nil, cloudprovider.InstanceNotFound
		}
		return nil, err
	}
	return instance, nil
}
func (g *Cloud) InstanceShutdownByProviderID(ctx context.Context, providerID string) (bool, error) {
	return false, cloudprovider.NotImplemented
}
func (g *Cloud) InstanceShutdown(ctx context.Context, node *v1.Node) (bool, error) {
	return false, cloudprovider.NotImplemented
}
func nodeAddressesFromInstance(instance *compute.Instance) ([]v1.NodeAddress, error) {
	if len(instance.NetworkInterfaces) < 1 {
		return nil, fmt.Errorf("could not find network interfaces for instanceID %q", instance.Id)
	}
	nodeAddresses := []v1.NodeAddress{}
	for _, nic := range instance.NetworkInterfaces {
		nodeAddresses = append(nodeAddresses, v1.NodeAddress{Type: v1.NodeInternalIP, Address: nic.NetworkIP})
		for _, config := range nic.AccessConfigs {
			nodeAddresses = append(nodeAddresses, v1.NodeAddress{Type: v1.NodeExternalIP, Address: config.NatIP})
		}
	}
	return nodeAddresses, nil
}
func (g *Cloud) InstanceTypeByProviderID(ctx context.Context, providerID string) (string, error) {
	instance, err := g.instanceByProviderID(providerID)
	if err != nil {
		return "", err
	}
	return instance.Type, nil
}
func (g *Cloud) InstanceExistsByProviderID(ctx context.Context, providerID string) (bool, error) {
	_, err := g.instanceByProviderID(providerID)
	if err != nil {
		if err == cloudprovider.InstanceNotFound {
			return false, nil
		}
		return false, err
	}
	return true, nil
}
func (g *Cloud) InstanceExists(ctx context.Context, node *v1.Node) (bool, error) {
	providerID := node.Spec.ProviderID
	if providerID == "" {
		var err error
		if providerID, err = cloudprovider.GetInstanceProviderID(ctx, g, types.NodeName(node.Name)); err != nil {
			if err == cloudprovider.InstanceNotFound {
				return false, nil
			}
			return false, err
		}
	}
	return g.InstanceExistsByProviderID(ctx, providerID)
}
func (g *Cloud) InstanceMetadata(ctx context.Context, node *v1.Node) (*cloudprovider.InstanceMetadata, error) {
	timeoutCtx, cancel := context.WithTimeout(ctx, 1*time.Hour)
	defer cancel()
	providerID := node.Spec.ProviderID
	if providerID == "" {
		var err error
		if providerID, err = cloudprovider.GetInstanceProviderID(ctx, g, types.NodeName(node.Name)); err != nil {
			return nil, err
		}
	}
	_, zone, name, err := splitProviderID(providerID)
	if err != nil {
		return nil, err
	}
	region, err := GetGCERegion(zone)
	if err != nil {
		return nil, err
	}
	instance, err := g.c.Instances().Get(timeoutCtx, meta.ZonalKey(canonicalizeInstanceName(name), zone))
	if err != nil {
		return nil, fmt.Errorf("error while querying for providerID %q: %v", providerID, err)
	}
	addresses, err := nodeAddressesFromInstance(instance)
	if err != nil {
		return nil, err
	}
	return &cloudprovider.InstanceMetadata{
		ProviderID:    providerID,
		InstanceType:  lastComponent(instance.MachineType),
		NodeAddresses: addresses,
		Zone:          zone,
		Region:        region,
	}, nil
}
func (g *Cloud) InstanceID(ctx context.Context, nodeName types.NodeName) (string, error) {
	instanceName := mapNodeNameToInstanceName(nodeName)
	if g.useMetadataServer {
		if g.isCurrentInstance(instanceName) {
			projectID, zone, err := getProjectAndZone()
			if err == nil {
				return projectID + "/" + zone + "/" + canonicalizeInstanceName(instanceName), nil
			}
		}
	}
	instance, err := g.getInstanceByName(instanceName)
	if err != nil {
		return "", err
	}
	return g.projectID + "/" + instance.Zone + "/" + instance.Name, nil
}
func (g *Cloud) InstanceType(ctx context.Context, nodeName types.NodeName) (string, error) {
	instanceName := mapNodeNameToInstanceName(nodeName)
	if g.useMetadataServer {
		if g.isCurrentInstance(instanceName) {
			mType, err := getCurrentMachineTypeViaMetadata()
			if err == nil {
				return mType, nil
			}
		}
	}
	instance, err := g.getInstanceByName(instanceName)
	if err != nil {
		return "", err
	}
	return instance.Type, nil
}
func (g *Cloud) AddSSHKeyToAllInstances(ctx context.Context, user string, keyData []byte) error {
	ctx, cancel := context.WithTimeout(ctx, 1*time.Hour)
	defer cancel()
	return wait.Poll(2*time.Second, 30*time.Second, func() (bool, error) {
		project, err := g.c.Projects().Get(ctx, g.projectID)
		if err != nil {
			klog.Errorf("Could not get project: %v", err)
			return false, nil
		}
		keyString := fmt.Sprintf("%s:%s %s@%s", user, strings.TrimSpace(string(keyData)), user, user)
		found := false
		for _, item := range project.CommonInstanceMetadata.Items {
			if item.Key == "sshKeys" {
				if strings.Contains(*item.Value, keyString) {
					klog.Info("SSHKey already in project metadata")
					return true, nil
				}
				value := *item.Value + "\n" + keyString
				item.Value = &value
				found = true
				break
			}
		}
		if !found {
			klog.Infof("Failed to find sshKeys metadata, creating a new item")
			project.CommonInstanceMetadata.Items = append(project.CommonInstanceMetadata.Items,
				&compute.MetadataItems{
					Key:   "sshKeys",
					Value: &keyString,
				})
		}
		mc := newInstancesMetricContext("add_ssh_key", "")
		err = g.c.Projects().SetCommonInstanceMetadata(ctx, g.projectID, project.CommonInstanceMetadata)
		mc.Observe(err)
		if err != nil {
			klog.Errorf("Could not Set Metadata: %v", err)
			return false, nil
		}
		klog.Infof("Successfully added sshKey to project metadata")
		return true, nil
	})
}
func (g *Cloud) GetAllCurrentZones() (sets.String, error) {
	if g.nodeInformerSynced == nil {
		klog.Warning("Cloud object does not have informers set, should only happen in E2E binary.")
		return g.GetAllZonesFromCloudProvider()
	}
	g.nodeZonesLock.Lock()
	defer g.nodeZonesLock.Unlock()
	if !g.nodeInformerSynced() {
		return nil, fmt.Errorf("node informer is not synced when trying to GetAllCurrentZones")
	}
	zones := sets.NewString()
	for zone, nodes := range g.nodeZones {
		if len(nodes) > 0 {
			zones.Insert(zone)
		}
	}
	return zones, nil
}
func (g *Cloud) GetAllZonesFromCloudProvider() (sets.String, error) {
	ctx, cancel := cloud.ContextWithCallTimeout()
	defer cancel()
	zones := sets.NewString()
	for _, zone := range g.managedZones {
		instances, err := g.c.Instances().List(ctx, zone, filter.None)
		if err != nil {
			return sets.NewString(), err
		}
		if len(instances) > 0 {
			zones.Insert(zone)
		}
	}
	return zones, nil
}
func (g *Cloud) InsertInstance(project string, zone string, i *compute.Instance) error {
	ctx, cancel := cloud.ContextWithCallTimeout()
	defer cancel()
	mc := newInstancesMetricContext("create", zone)
	return mc.Observe(g.c.Instances().Insert(ctx, meta.ZonalKey(i.Name, zone), i))
}