/
get_service_instance.go
107 lines (95 loc) · 3.31 KB
/
get_service_instance.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
/*
* Copyright 2022 VMware, Inc.
*
* 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 cf
import (
"context"
"fmt"
"strings"
"time"
"github.com/pkg/errors"
"github.com/vmware-tanzu/service-instance-migrator-for-cloud-foundry/pkg/exec"
"github.com/vmware-tanzu/service-instance-migrator-for-cloud-foundry/pkg/flow"
"github.com/vmware-tanzu/service-instance-migrator-for-cloud-foundry/pkg/log"
)
func GetServiceInstance(e exec.Executor, cfHome string, instance *ServiceInstance, duration time.Duration, pause time.Duration) flow.StepFunc {
return func(ctx context.Context, config interface{}, dryRun bool) (flow.Result, error) {
log.Infof("Waiting for '%s' service instance to become ready", instance.Name)
res, err := executeForDuration(ctx, e, []string{
fmt.Sprintf("CF_HOME='%s' cf service '%s' | grep -i 'status:' | awk '{print $NF}'", cfHome, instance.Name),
}, duration, pause, func(result exec.Result) bool {
return strings.Contains(result.Output, "succeeded")
}, func(result exec.Result) error {
if strings.Contains(result.Output, "failed") {
return fmt.Errorf("'%s' is in a failed state", instance.Name)
}
return nil
})
if err != nil {
return exec.Result{}, fmt.Errorf("failed to check service instance status: %w", err)
}
res, err = getServiceInstance(ctx, e, cfHome, *instance)
if err != nil {
return exec.Result{}, fmt.Errorf("failed to get service instance guid for '%s': %w", instance.Name, err)
}
instance.GUID = strings.TrimSuffix(res.Output, "\n")
log.Debugf("Service instance %q created", instance.GUID)
return exec.Result{}, nil
}
}
func getServiceInstance(ctx context.Context, e exec.Executor, cfHome string, instance ServiceInstance) (exec.Result, error) {
lines := []string{
fmt.Sprintf("CF_HOME='%s' cf service '%s' --guid", cfHome, instance.Name),
}
return e.Execute(ctx, strings.NewReader(strings.Join(lines, "\n")))
}
func executeForDuration(ctx context.Context, s exec.Executor, lines []string, timeout time.Duration, pause time.Duration, doneCondition func(exec.Result) bool, errorCondition func(exec.Result) error) (exec.Result, error) {
done := make(chan bool)
var err error
var res exec.Result
child, cancel := context.WithCancel(ctx)
defer cancel()
go func() {
for {
select {
case <-done:
return
default:
}
res, err = s.Execute(ctx, strings.NewReader(strings.Join(lines, "\n")))
if err != nil {
cancel()
return
}
if err = errorCondition(res); err != nil {
cancel()
return
}
if doneCondition(res) || res.DryRun {
close(done)
continue
}
time.Sleep(pause)
}
}()
select {
case <-done:
return res, nil
case <-child.Done():
log.Debugln("context was cancelled")
return res, err
case <-time.After(timeout):
close(done)
return res, errors.New("timed out waiting for backup")
}
}