mirror of
https://github.com/kubernetes/node-problem-detector.git
synced 2026-03-02 09:40:29 +00:00
181 lines
5.2 KiB
Go
181 lines
5.2 KiB
Go
/*
|
|
Copyright 2018 The Kubernetes Authors.
|
|
|
|
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 gce
|
|
|
|
import (
|
|
"fmt"
|
|
"os/exec"
|
|
"time"
|
|
|
|
"k8s.io/node-problem-detector/test/e2e/lib/ssh"
|
|
|
|
. "github.com/onsi/gomega"
|
|
compute "google.golang.org/api/compute/v1"
|
|
)
|
|
|
|
// Instance represents a GCE instance.
|
|
type Instance struct {
|
|
Name string
|
|
Zone string
|
|
Project string
|
|
MachineType string
|
|
ExternalIP string
|
|
SshKey string
|
|
SshUser string
|
|
ComputeService *compute.Service
|
|
}
|
|
|
|
// CreateInstance creates a GCE instance with provided spec.
|
|
func CreateInstance(instance Instance, imageName string, imageProject string) (Instance, error) {
|
|
if instance.MachineType == "" {
|
|
instance.MachineType = "n1-standard-1"
|
|
}
|
|
|
|
p, err := instance.ComputeService.Projects.Get(instance.Project).Do()
|
|
if err != nil {
|
|
return instance, fmt.Errorf("failed to get project info %q: %v", instance.Project, err)
|
|
}
|
|
|
|
i := &compute.Instance{
|
|
Name: instance.Name,
|
|
MachineType: fmt.Sprintf("zones/%s/machineTypes/%s", instance.Zone, instance.MachineType),
|
|
NetworkInterfaces: []*compute.NetworkInterface{
|
|
{
|
|
AccessConfigs: []*compute.AccessConfig{
|
|
{
|
|
Type: "ONE_TO_ONE_NAT",
|
|
Name: "External NAT",
|
|
},
|
|
}},
|
|
},
|
|
Disks: []*compute.AttachedDisk{
|
|
{
|
|
AutoDelete: true,
|
|
Boot: true,
|
|
Type: "PERSISTENT",
|
|
InitializeParams: &compute.AttachedDiskInitializeParams{
|
|
SourceImage: fmt.Sprintf("projects/%s/global/images/%s", imageProject, imageName),
|
|
DiskSizeGb: 20,
|
|
},
|
|
},
|
|
},
|
|
ServiceAccounts: []*compute.ServiceAccount{
|
|
{
|
|
Email: p.DefaultServiceAccount,
|
|
Scopes: []string{
|
|
"https://www.googleapis.com/auth/cloud-platform",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
if _, err := instance.ComputeService.Instances.Get(instance.Project, instance.Zone, instance.Name).Do(); err != nil {
|
|
op, err := instance.ComputeService.Instances.Insert(instance.Project, instance.Zone, i).Do()
|
|
if err != nil {
|
|
ret := fmt.Sprintf("could not create instance %s: API error: %v", instance.Name, err)
|
|
if op != nil {
|
|
ret = fmt.Sprintf("%s: %v", ret, op.Error)
|
|
}
|
|
return instance, fmt.Errorf(ret)
|
|
} else if op.Error != nil {
|
|
return instance, fmt.Errorf("could not create instance %s: %+v", instance.Name, op.Error)
|
|
}
|
|
}
|
|
|
|
instanceRunning := false
|
|
// Waiting for the instance to be SSH-able by retrying SSH with timeout of 5 min (15*20sec)
|
|
for i := 0; i < 15 && !instanceRunning; i++ {
|
|
if i > 0 {
|
|
time.Sleep(time.Second * 20)
|
|
}
|
|
if instance.ExternalIP == "" {
|
|
instance.populateExternalIP()
|
|
}
|
|
|
|
result := ssh.Run("pwd", instance.ExternalIP, instance.SshUser, instance.SshKey)
|
|
if result.SSHError != nil {
|
|
err = fmt.Errorf("SSH to instance %s failed: %s", instance.Name, result.SSHError)
|
|
continue
|
|
}
|
|
instanceRunning = true
|
|
}
|
|
|
|
if !instanceRunning {
|
|
return instance, err
|
|
}
|
|
return instance, nil
|
|
}
|
|
|
|
func (ins *Instance) populateExternalIP() {
|
|
gceInstance, err := ins.ComputeService.Instances.Get(ins.Project, ins.Zone, ins.Name).Do()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
for i := range gceInstance.NetworkInterfaces {
|
|
ni := gceInstance.NetworkInterfaces[i]
|
|
for j := range ni.AccessConfigs {
|
|
ac := ni.AccessConfigs[j]
|
|
if len(ac.NatIP) > 0 {
|
|
ins.ExternalIP = ac.NatIP
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// RunCommand runs a command on the GCE instance and returns the command result.
|
|
func (ins *Instance) RunCommand(cmd string) ssh.Result {
|
|
if ins.ExternalIP == "" {
|
|
ins.populateExternalIP()
|
|
}
|
|
return ssh.Run(cmd, ins.ExternalIP, ins.SshUser, ins.SshKey)
|
|
}
|
|
|
|
// RunCommand runs a command on the GCE instance and returns the command result, and fails the test when the command failed.
|
|
func (ins *Instance) RunCommandOrFail(cmd string) ssh.Result {
|
|
result := ins.RunCommand(cmd)
|
|
Expect(result.SSHError).ToNot(HaveOccurred(), "SSH-ing to the instance failed: %v\n", result)
|
|
Expect(result.Code).To(Equal(0), "Running command failed: %v\n", result)
|
|
return result
|
|
}
|
|
|
|
// PushFile pushes a local file to a GCE instance.
|
|
func (ins *Instance) PushFile(srcPath, destPath string) error {
|
|
if ins.ExternalIP == "" {
|
|
ins.populateExternalIP()
|
|
}
|
|
output, err := exec.Command("scp", "-o", "StrictHostKeyChecking no",
|
|
"-i", ins.SshKey,
|
|
srcPath, fmt.Sprintf("%s@%s:%s", ins.SshUser, ins.ExternalIP, destPath)).CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("Error running scp: %v.\nHere is the output for the command: %v", err, string(output))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DeleteInstance deletes a GCE instance.
|
|
func (ins *Instance) DeleteInstance() error {
|
|
if _, err := ins.ComputeService.Instances.Get(ins.Project, ins.Zone, ins.Name).Do(); err != nil {
|
|
return err
|
|
}
|
|
if _, err := ins.ComputeService.Instances.Delete(ins.Project, ins.Zone, ins.Name).Do(); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|