-
Notifications
You must be signed in to change notification settings - Fork 96
/
reconciler.go
148 lines (123 loc) · 4.97 KB
/
reconciler.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
144
145
146
147
148
package datasync
import (
"context"
"fmt"
"io"
"io/ioutil"
"net/http"
"path/filepath"
integreatlyv1alpha1 "github.com/integr8ly/integreatly-operator/pkg/apis/integreatly/v1alpha1"
"github.com/integr8ly/integreatly-operator/pkg/config"
"github.com/integr8ly/integreatly-operator/pkg/resources"
"github.com/integr8ly/integreatly-operator/pkg/resources/events"
"github.com/integr8ly/integreatly-operator/pkg/resources/marketplace"
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/record"
k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)
const (
datasyncNs = "openshift"
templatesBaseURL = "https://raw.githubusercontent.com/aerogear/datasync-deployment/"
openshiftTemplatesFolder = "/openshift/"
)
var (
datasyncTemplates = []string{
"datasync-http.yml",
"datasync-showcase.yml",
}
)
type Reconciler struct {
*resources.Reconciler
coreClient kubernetes.Interface
Config *config.DataSync
ConfigManager config.ConfigReadWriter
httpClient http.Client
logger *logrus.Entry
recorder record.EventRecorder
installation *integreatlyv1alpha1.RHMI
}
func (r *Reconciler) GetPreflightObject(ns string) runtime.Object {
return nil
}
func NewReconciler(configManager config.ConfigReadWriter, installation *integreatlyv1alpha1.RHMI, mpm marketplace.MarketplaceInterface, recorder record.EventRecorder) (*Reconciler, error) {
config, err := configManager.ReadDataSync()
if err != nil {
return nil, fmt.Errorf("could not retrieve %s config: %w", integreatlyv1alpha1.ProductDataSync, err)
}
if config.GetNamespace() == "" {
config.SetNamespace(datasyncNs)
}
if err = config.Validate(); err != nil {
return nil, fmt.Errorf("%s config is not valid: %w", integreatlyv1alpha1.ProductDataSync, err)
}
logger := logrus.NewEntry(logrus.StandardLogger())
var httpClient http.Client
return &Reconciler{
ConfigManager: configManager,
Config: config,
logger: logger,
httpClient: httpClient,
Reconciler: resources.NewReconciler(mpm),
recorder: recorder,
installation: installation,
}, nil
}
func (r *Reconciler) Reconcile(ctx context.Context, installation *integreatlyv1alpha1.RHMI, product *integreatlyv1alpha1.RHMIProductStatus, serverClient k8sclient.Client) (integreatlyv1alpha1.StatusPhase, error) {
phase, err := r.reconcileTemplates(ctx, serverClient)
if err != nil || phase != integreatlyv1alpha1.PhaseCompleted {
events.HandleError(r.recorder, installation, phase, "Failed to reconcile configmap", err)
return phase, err
}
product.Version = r.Config.GetProductVersion()
events.HandleProductComplete(r.recorder, installation, integreatlyv1alpha1.ProductsStage, r.Config.GetProductName())
return integreatlyv1alpha1.PhaseCompleted, nil
}
func (r *Reconciler) reconcileTemplates(ctx context.Context, serverClient k8sclient.Client) (integreatlyv1alpha1.StatusPhase, error) {
for _, templateFn := range datasyncTemplates {
fileUrl := templatesBaseURL + string(r.Config.GetProductVersion()) + openshiftTemplatesFolder + templateFn
fileData, err := r.getFileContentFromURL(fileUrl)
if err != nil {
return integreatlyv1alpha1.PhaseFailed, fmt.Errorf("failed to get file contents of %s: %w", templateFn, err)
}
content, err := ioutil.ReadAll(fileData)
if err != nil {
return integreatlyv1alpha1.PhaseFailed, fmt.Errorf("failed to read contents of %s: %w", templateFn, err)
}
if filepath.Ext(templateFn) == ".yml" || filepath.Ext(templateFn) == ".yaml" {
content, err = yaml.ToJSON(content)
if err != nil {
return integreatlyv1alpha1.PhaseFailed, fmt.Errorf("failed to convert yaml to json %s: %w", templateFn, err)
}
}
templateRuntimeObj, err := resources.LoadKubernetesResource(content, r.Config.GetNamespace())
if err != nil {
return integreatlyv1alpha1.PhaseFailed, fmt.Errorf("failed to load resource %s: %w", templateFn, err)
}
templateUnstructured, err := resources.UnstructuredFromRuntimeObject(templateRuntimeObj)
if err != nil {
return integreatlyv1alpha1.PhaseFailed, fmt.Errorf("failed to parse object: %w", err)
}
if _, err := controllerutil.CreateOrUpdate(ctx, serverClient, templateUnstructured, func() error {
ownerutil.EnsureOwner(templateUnstructured, r.installation)
return nil
}); err != nil {
return integreatlyv1alpha1.PhaseFailed, fmt.Errorf("Error reconciling datasync template %s: %w", templateUnstructured.GetName(), err)
}
}
return integreatlyv1alpha1.PhaseCompleted, nil
}
func (r *Reconciler) getFileContentFromURL(url string) (io.ReadCloser, error) {
resp, err := r.httpClient.Get(url)
if err != nil {
return nil, err
}
if resp.StatusCode == http.StatusOK {
return resp.Body, nil
}
return nil, fmt.Errorf("failed to get file content from %s. Status: %d", url, resp.StatusCode)
}