k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/e2e_node/remote/gce/gcloud.go (about)

     1  /*
     2  Copyright 2024 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package gce
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"os/exec"
    23  )
    24  
    25  type gceImage struct {
    26  	CreationTimestamp string `json:"creationTimestamp"`
    27  	Family            string `json:"family"`
    28  	ID                string `json:"id"`
    29  	Name              string `json:"name"`
    30  }
    31  
    32  type gceMetadata struct {
    33  	Fingerprint string             `json:"fingerprint"`
    34  	Kind        string             `json:"kind"`
    35  	Items       []gceMetadataItems `json:"items,omitempty"`
    36  }
    37  
    38  type gceMetadataItems struct {
    39  	Key   string `json:"key,omitempty"`
    40  	Value string `json:"value,omitempty"`
    41  }
    42  
    43  type gceAccessConfigs struct {
    44  	Type  string `json:"type"`
    45  	Name  string `json:"name"`
    46  	NatIP string `json:"natIP,omitempty"`
    47  }
    48  
    49  type gceNetworkInterfaces struct {
    50  	AccessConfigs []gceAccessConfigs `json:"accessConfigs"`
    51  }
    52  
    53  type gceInstance struct {
    54  	CreationTimestamp       string                 `json:"creationTimestamp"`
    55  	Description             string                 `json:"description"`
    56  	Fingerprint             string                 `json:"fingerprint"`
    57  	ID                      string                 `json:"id"`
    58  	KeyRevocationActionType string                 `json:"keyRevocationActionType"`
    59  	Kind                    string                 `json:"kind"`
    60  	LabelFingerprint        string                 `json:"labelFingerprint"`
    61  	LastStartTimestamp      string                 `json:"lastStartTimestamp"`
    62  	MachineType             string                 `json:"machineType"`
    63  	Metadata                gceMetadata            `json:"metadata"`
    64  	Name                    string                 `json:"name"`
    65  	NetworkInterfaces       []gceNetworkInterfaces `json:"networkInterfaces"`
    66  	Status                  string                 `json:"status"`
    67  }
    68  
    69  type projectInfo struct {
    70  	CommonInstanceMetadata struct {
    71  		Fingerprint string `json:"fingerprint"`
    72  		Items       []struct {
    73  			Key   string `json:"key"`
    74  			Value string `json:"value"`
    75  		} `json:"items"`
    76  		Kind string `json:"kind"`
    77  	} `json:"commonInstanceMetadata"`
    78  	CreationTimestamp     string `json:"creationTimestamp"`
    79  	DefaultNetworkTier    string `json:"defaultNetworkTier"`
    80  	DefaultServiceAccount string `json:"defaultServiceAccount"`
    81  	ID                    string `json:"id"`
    82  }
    83  
    84  func runGCPCommandWithZone(args ...string) ([]byte, error) {
    85  	if zone != nil && len(*zone) > 0 {
    86  		args = append(args, "--zone="+*zone)
    87  	}
    88  	return runGCPCommand(args...)
    89  }
    90  
    91  func runGCPCommandWithZones(args ...string) ([]byte, error) {
    92  	if zone != nil && len(*zone) > 0 {
    93  		args = append(args, "--zones="+*zone+",")
    94  	}
    95  	return runGCPCommand(args...)
    96  }
    97  
    98  func runGCPCommand(args ...string) ([]byte, error) {
    99  	if project != nil && len(*project) > 0 {
   100  		args = append(args, "--project="+*project)
   101  	}
   102  	return runGCPCommandNoProject(args...)
   103  }
   104  
   105  func runGCPCommandNoProject(args ...string) ([]byte, error) {
   106  	bytes, err := exec.Command("gcloud", args...).Output()
   107  	if err != nil {
   108  		var message string
   109  		if ee, ok := err.(*exec.ExitError); ok {
   110  			message = fmt.Sprintf("%v\n%v", ee, string(ee.Stderr))
   111  		} else {
   112  			message = fmt.Sprintf("%v", err)
   113  		}
   114  		return nil, fmt.Errorf("unable to run gcloud command\n %s \n %w", message, err)
   115  	}
   116  	return bytes, nil
   117  }
   118  
   119  func getGCEInstance(host string) (*gceInstance, error) {
   120  	data, err := runGCPCommandWithZone("compute", "instances", "describe", host, "--format=json")
   121  	if err != nil {
   122  		return nil, fmt.Errorf("failed to describe instance in project %q: %w", *project, err)
   123  	}
   124  
   125  	var gceHost gceInstance
   126  	err = json.Unmarshal(data, &gceHost)
   127  	if err != nil {
   128  		return nil, fmt.Errorf("failed to parse instance: %w", err)
   129  	}
   130  	return &gceHost, nil
   131  }
   132  
   133  func (g *GCERunner) getSerialOutput(host string) (string, error) {
   134  	data, err := runGCPCommandWithZone("compute", "instances", "get-serial-port-output", "--port=1", host)
   135  	if err != nil {
   136  		return "", fmt.Errorf("failed to describe instance in project %q: %w", *project, err)
   137  	}
   138  	return string(data), nil
   139  }