This repository has been archived by the owner on Jan 11, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 560
/
service.go
143 lines (130 loc) · 3.59 KB
/
service.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package service
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os/exec"
"regexp"
"time"
"github.com/Azure/acs-engine/test/e2e/kubernetes/util"
)
// Service represents a kubernetes service
type Service struct {
Metadata Metadata `json:"metadata"`
Spec Spec `json:"spec"`
Status Status `json:"status"`
}
// Metadata holds information like name, namespace, and labels
type Metadata struct {
CreatedAt time.Time `json:"creationTimestamp"`
Labels map[string]string `json:"labels"`
Name string `json:"name"`
Namespace string `json:"namespace"`
}
// Spec holds information like clusterIP and port
type Spec struct {
ClusterIP string `json:"clusterIP"`
Ports []Port `json:"ports"`
Type string `json:"type"`
}
// Port represents a service port definition
type Port struct {
NodePort int `json:"nodePort"`
Port int `json:"port"`
Protocol string `json:"protocol"`
TargetPort int `json:"targetPort"`
}
// Status holds the load balancer definition
type Status struct {
LoadBalancer LoadBalancer `json:"loadBalancer"`
}
// LoadBalancer holds the ingress definitions
type LoadBalancer struct {
Ingress []map[string]string `json:"ingress"`
}
// Get returns the service definition specified in a given namespace
func Get(name, namespace string) (*Service, error) {
cmd := exec.Command("kubectl", "get", "svc", "-o", "json", "-n", namespace, name)
util.PrintCommand(cmd)
out, err := cmd.CombinedOutput()
if err != nil {
log.Printf("Error trying to run 'kubectl get svc':%s\n", string(out))
return nil, err
}
s := Service{}
err = json.Unmarshal(out, &s)
if err != nil {
log.Printf("Error unmarshalling service json:%s\n", err)
return nil, err
}
return &s, nil
}
// Delete will delete a service in a given namespace
func (s *Service) Delete() error {
cmd := exec.Command("kubectl", "delete", "svc", "-n", s.Metadata.Namespace, s.Metadata.Name)
util.PrintCommand(cmd)
out, err := cmd.CombinedOutput()
if err != nil {
log.Printf("Error while trying to delete service %s in namespace %s:%s\n", s.Metadata.Namespace, s.Metadata.Name, string(out))
return err
}
return nil
}
// GetNodePort will return the node port for a given pod
func (s *Service) GetNodePort(port int) int {
for _, p := range s.Spec.Ports {
if p.Port == port {
return p.NodePort
}
}
return 0
}
// WaitForExternalIP waits for an external ip to be provisioned
func (s *Service) WaitForExternalIP(wait, sleep time.Duration) (*Service, error) {
svcCh := make(chan *Service)
errCh := make(chan error)
ctx, cancel := context.WithTimeout(context.Background(), wait)
defer cancel()
go func() {
for {
select {
case <-ctx.Done():
errCh <- fmt.Errorf("Timeout exceeded while waiting for External IP to be provisioned")
default:
svc, _ := Get(s.Metadata.Name, s.Metadata.Namespace)
if svc != nil && svc.Status.LoadBalancer.Ingress != nil {
svcCh <- svc
}
time.Sleep(sleep)
}
}
}()
for {
select {
case err := <-errCh:
return nil, err
case svc := <-svcCh:
return svc, nil
}
}
}
// Validate will attempt to run an http.Get against the root service url
func (s *Service) Validate(check string, attempts int, sleep time.Duration) bool {
for i := 0; i < attempts; i++ {
url := fmt.Sprintf("http://%s", s.Status.LoadBalancer.Ingress[0]["ip"])
resp, err := http.Get(url)
if err == nil {
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
matched, _ := regexp.MatchString(check, string(body))
if matched == true {
return true
}
}
time.Sleep(sleep)
}
return false
}