Skip to content

Commit 92ccb0d

Browse files
committed
[tests] Minor improvements
1 parent ecd7347 commit 92ccb0d

File tree

13 files changed

+282
-188
lines changed

13 files changed

+282
-188
lines changed

.werft/run-integration-tests.yaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ args:
55
- name: namespace
66
desc: "The namespace to run the integration test against"
77
required: true
8+
- name: username
9+
desc: "The username to run the integration test with"
10+
required: false
811
pod:
912
serviceAccount: werft
1013
nodeSelector:
@@ -62,9 +65,15 @@ pod:
6265
cp -R /config/gcloud /root/.config/gcloud
6366
export GOOGLE_APPLICATION_CREDENTIALS=/config/gcloud/legacy_credentials/[email protected]/adc.json
6467
echo "[prep] received config."
68+
69+
USERNAME="{{ .Annotations.username }}"
70+
if [[ "$USERNAME" == "<no value>" ]]; then
71+
USERNAME=""
72+
fi
73+
echo "[prep] using username: $USERNAME"
6574
echo "[prep|DONE]"
6675
67-
/entrypoint.sh -kubeconfig=/config/kubeconfig -namespace={{ .Annotations.namespace }} 2>&1 | ts "[int-tests] "
76+
/entrypoint.sh -kubeconfig=/config/kubeconfig -namespace={{ .Annotations.namespace }} -username=$USERNAME 2>&1 | ts "[int-tests] "
6877
6978
RC=${PIPESTATUS[0]}
7079
if [ $RC -eq 1 ]; then echo "[int-tests|FAIL]"; else echo "[int-tests|DONE]"; fi

test/pkg/integration/apis.go

Lines changed: 146 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"errors"
1212
"fmt"
1313
"net/url"
14+
"strconv"
1415
"strings"
1516
"time"
1617

@@ -65,16 +66,27 @@ type ComponentAPI struct {
6566
BlobServiceClient csapi.BlobServiceClient
6667
}
6768
dbStatus struct {
68-
Port int
69-
Password string
70-
DB *sql.DB
69+
Config *DBConfig
70+
DB *sql.DB
7171
}
7272
imgbldStatus struct {
7373
Port int
7474
Client imgbldr.ImageBuilderClient
7575
}
7676
}
7777

78+
type DBConfig struct {
79+
Host string
80+
Port int32
81+
ForwardPort *ForwardPort
82+
Password string
83+
}
84+
85+
type ForwardPort struct {
86+
PodName string
87+
RemotePort int32
88+
}
89+
7890
// Supervisor provides a gRPC connection to a workspace's supervisor
7991
func (c *ComponentAPI) Supervisor(instanceID string) (res grpc.ClientConnInterface) {
8092
pod, _, err := c.t.selectPod(ComponentWorkspace, selectPodOptions{InstanceID: instanceID})
@@ -370,81 +382,31 @@ func (c *ComponentAPI) DB() *sql.DB {
370382
c.t.t.Fatalf("cannot access database: %q", rerr)
371383
}()
372384

373-
if c.dbStatus.Port == 0 {
374-
svc, err := c.t.clientset.CoreV1().Services(c.t.namespace).Get(context.Background(), "db", metav1.GetOptions{})
375-
if err != nil {
376-
rerr = err
377-
return nil
378-
}
379-
pods, err := c.t.clientset.CoreV1().Pods(c.t.namespace).List(context.Background(), metav1.ListOptions{
380-
LabelSelector: labels.SelectorFromSet(svc.Spec.Selector).String(),
381-
})
385+
if c.dbStatus.Config == nil {
386+
config, err := c.findDBConfig()
382387
if err != nil {
383388
rerr = err
384389
return nil
385390
}
386-
if len(pods.Items) == 0 {
387-
rerr = xerrors.Errorf("no pods for service %s found", svc.Name)
388-
return nil
389-
}
390-
var pod *corev1.Pod
391-
for _, p := range pods.Items {
392-
if p.Spec.NodeName == "" {
393-
// no node means the pod can't be ready
394-
continue
395-
}
396-
var isReady bool
397-
for _, cond := range p.Status.Conditions {
398-
if cond.Type == corev1.PodReady {
399-
isReady = cond.Status == corev1.ConditionTrue
400-
break
401-
}
402-
}
403-
if !isReady {
404-
continue
405-
}
406-
407-
pod = &p
408-
break
409-
}
410-
if pod == nil {
411-
rerr = xerrors.Errorf("no active pod for service %s found", svc.Name)
412-
return nil
413-
}
391+
c.dbStatus.Config = config
392+
}
393+
config := c.dbStatus.Config
414394

415-
localPort, err := getFreePort()
416-
if err != nil {
417-
rerr = err
418-
return nil
419-
}
395+
// if configured: setup local port-forward to DB pod
396+
if config.ForwardPort != nil {
420397
ctx, cancel := context.WithCancel(context.Background())
421-
ready, errc := forwardPort(ctx, c.t.restConfig, c.t.namespace, pod.Name, fmt.Sprintf("%d:3306", localPort))
398+
ready, errc := forwardPort(ctx, c.t.restConfig, c.t.namespace, config.ForwardPort.PodName, fmt.Sprintf("%d:%d", config.Port, config.ForwardPort.RemotePort))
422399
select {
423-
case err = <-errc:
400+
case err := <-errc:
424401
cancel()
425402
rerr = err
426403
return nil
427404
case <-ready:
428405
}
429406
c.t.closer = append(c.t.closer, func() error { cancel(); return nil })
430-
431-
c.dbStatus.Port = localPort
432-
}
433-
if c.dbStatus.Password == "" {
434-
sct, err := c.t.clientset.CoreV1().Secrets(c.t.namespace).Get(context.Background(), "db-password", metav1.GetOptions{})
435-
if err != nil {
436-
rerr = err
437-
return nil
438-
}
439-
pwd, ok := sct.Data["mysql-root-password"]
440-
if !ok {
441-
rerr = xerrors.Errorf("no mysql-root-password data present in secret %s", sct.Name)
442-
return nil
443-
}
444-
c.dbStatus.Password = string(pwd)
445407
}
446408

447-
db, err := sql.Open("mysql", fmt.Sprintf("gitpod:%s@tcp(127.0.0.1:%d)/gitpod", c.dbStatus.Password, c.dbStatus.Port))
409+
db, err := sql.Open("mysql", fmt.Sprintf("gitpod:%s@tcp(%s:%d)/gitpod", config.Password, config.Host, config.Port))
448410
if err != nil {
449411
rerr = err
450412
return nil
@@ -455,6 +417,127 @@ func (c *ComponentAPI) DB() *sql.DB {
455417
return db
456418
}
457419

420+
func (c *ComponentAPI) findDBConfig() (*DBConfig, error) {
421+
config, err := c.findDBConfigFromPodEnv("server")
422+
if err != nil {
423+
return nil, err
424+
}
425+
426+
// here we _assume_ that "config" points to a service: find us a concrete DB pod to forward to
427+
svc, err := c.t.clientset.CoreV1().Services(c.t.namespace).Get(context.Background(), config.Host, metav1.GetOptions{})
428+
if err != nil {
429+
return nil, err
430+
}
431+
432+
// find remotePort
433+
var remotePort int32
434+
for _, p := range svc.Spec.Ports {
435+
if p.Port == config.Port {
436+
remotePort = p.TargetPort.IntVal
437+
if remotePort == 0 {
438+
remotePort = p.Port
439+
}
440+
break
441+
}
442+
}
443+
if remotePort == 0 {
444+
return nil, fmt.Errorf("no ports found on service: %s", svc.Name)
445+
}
446+
447+
// find pod to forward to
448+
pods, err := c.t.clientset.CoreV1().Pods(c.t.namespace).List(context.Background(), metav1.ListOptions{
449+
LabelSelector: labels.SelectorFromSet(svc.Spec.Selector).String(),
450+
})
451+
if err != nil {
452+
return nil, err
453+
}
454+
if len(pods.Items) == 0 {
455+
return nil, fmt.Errorf("no pods for service %s found", svc.Name)
456+
}
457+
var pod *corev1.Pod
458+
for _, p := range pods.Items {
459+
if p.Spec.NodeName == "" {
460+
// no node means the pod can't be ready
461+
continue
462+
}
463+
var isReady bool
464+
for _, cond := range p.Status.Conditions {
465+
if cond.Type == corev1.PodReady {
466+
isReady = cond.Status == corev1.ConditionTrue
467+
break
468+
}
469+
}
470+
if !isReady {
471+
continue
472+
}
473+
474+
pod = &p
475+
break
476+
}
477+
if pod == nil {
478+
return nil, fmt.Errorf("no active pod for service %s found", svc.Name)
479+
}
480+
481+
localPort, err := getFreePort()
482+
if err != nil {
483+
return nil, err
484+
}
485+
config.Port = int32(localPort)
486+
config.ForwardPort = &ForwardPort{
487+
RemotePort: remotePort,
488+
PodName: pod.Name,
489+
}
490+
config.Host = "127.0.0.1"
491+
492+
return config, nil
493+
}
494+
495+
func (c *ComponentAPI) findDBConfigFromPodEnv(componentName string) (*DBConfig, error) {
496+
lblSelector := fmt.Sprintf("component=%s", componentName)
497+
list, err := c.t.clientset.CoreV1().Pods(c.t.namespace).List(context.Background(), metav1.ListOptions{
498+
LabelSelector: lblSelector,
499+
})
500+
if err != nil {
501+
return nil, err
502+
}
503+
if len(list.Items) == 0 {
504+
return nil, fmt.Errorf("no pods found for: %s", lblSelector)
505+
}
506+
pod := list.Items[0]
507+
508+
var password string
509+
var port int32
510+
var host string
511+
OuterLoop:
512+
for _, c := range pod.Spec.Containers {
513+
for _, v := range c.Env {
514+
if v.Name == "DB_PASSWORD" {
515+
password = v.Value
516+
} else if v.Name == "DB_PORT" {
517+
pPort, err := strconv.Atoi(v.Value)
518+
if err != nil {
519+
return nil, fmt.Errorf("error parsing DB_PORT '%s' on pod %s!", v.Value, pod.Name)
520+
}
521+
port = int32(pPort)
522+
} else if v.Name == "DB_HOST" {
523+
host = v.Value
524+
}
525+
if password != "" && port != 0 && host != "" {
526+
break OuterLoop
527+
}
528+
}
529+
}
530+
if password == "" || port == 0 || host == "" {
531+
return nil, fmt.Errorf("could not find complete DBConfig on pod %s!", pod.Name)
532+
}
533+
config := DBConfig{
534+
Host: host,
535+
Port: port,
536+
Password: password,
537+
}
538+
return &config, nil
539+
}
540+
458541
// ImageBuilder provides access to the image builder service.
459542
func (c *ComponentAPI) ImageBuilder() imgbldr.ImageBuilderClient {
460543
if c.imgbldStatus.Client != nil {

0 commit comments

Comments
 (0)