/
manager.go
152 lines (133 loc) · 4.88 KB
/
manager.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
149
150
151
152
package deployer
import (
"github.com/sirupsen/logrus"
"github.com/rancher/fleet/internal/helmdeployer"
"github.com/rancher/fleet/internal/manifest"
fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
fleetcontrollers "github.com/rancher/fleet/pkg/generated/controllers/fleet.cattle.io/v1alpha1"
"github.com/rancher/wrangler/v2/pkg/apply"
"github.com/rancher/wrangler/v2/pkg/kv"
apierror "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
type Manager struct {
fleetNamespace string
defaultNamespace string
bundleDeploymentCache fleetcontrollers.BundleDeploymentCache
lookup manifest.Lookup
deployer *helmdeployer.Helm
apply apply.Apply
labelPrefix string
labelSuffix string
bundleDeploymentController fleetcontrollers.BundleDeploymentController
}
func NewManager(fleetNamespace string,
defaultNamespace string,
labelPrefix, labelSuffix string,
bundleDeploymentCache fleetcontrollers.BundleDeploymentCache,
bundleDeploymentController fleetcontrollers.BundleDeploymentController,
lookup manifest.Lookup,
deployer *helmdeployer.Helm,
apply apply.Apply) *Manager {
return &Manager{
fleetNamespace: fleetNamespace,
defaultNamespace: defaultNamespace,
labelPrefix: labelPrefix,
labelSuffix: labelSuffix,
bundleDeploymentCache: bundleDeploymentCache,
lookup: lookup,
deployer: deployer,
apply: apply.WithDynamicLookup(),
bundleDeploymentController: bundleDeploymentController,
}
}
// releaseKey returns a deploymentKey from namespace+releaseName
func (m *Manager) releaseKey(bd *fleet.BundleDeployment) string {
ns := m.defaultNamespace
if bd.Spec.Options.TargetNamespace != "" {
ns = bd.Spec.Options.TargetNamespace
} else if bd.Spec.Options.DefaultNamespace != "" {
ns = bd.Spec.Options.DefaultNamespace
}
if bd.Spec.Options.Helm == nil || bd.Spec.Options.Helm.ReleaseName == "" {
return ns + "/" + bd.Name
}
return ns + "/" + bd.Spec.Options.Helm.ReleaseName
}
func (m *Manager) Cleanup() error {
deployed, err := m.deployer.ListDeployments()
if err != nil {
return err
}
for _, deployed := range deployed {
bundleDeployment, err := m.bundleDeploymentCache.Get(m.fleetNamespace, deployed.BundleID)
if apierror.IsNotFound(err) {
// found a helm secret, but no bundle deployment, so uninstall the release
logrus.Infof("Deleting orphan bundle ID %s, release %s", deployed.BundleID, deployed.ReleaseName)
if err := m.deployer.Delete(deployed.BundleID, deployed.ReleaseName); err != nil {
return err
}
return nil
} else if err != nil {
return err
}
key := m.releaseKey(bundleDeployment)
if key != deployed.ReleaseName {
// found helm secret and bundle deployment for BundleID, but release name doesn't match, so delete the release
logrus.Infof("Deleting unknown bundle ID %s, release %s, expecting release %s", deployed.BundleID, deployed.ReleaseName, key)
if err := m.deployer.Delete(deployed.BundleID, deployed.ReleaseName); err != nil {
return err
}
}
}
return nil
}
func (m *Manager) Delete(bundleDeploymentKey string) error {
_, name := kv.RSplit(bundleDeploymentKey, "/")
return m.deployer.Delete(name, "")
}
// AllResources returns the resources that are deployed by the bundle deployment,
// according to the helm release history. It adds to be deleted resources to
// the list, by comparing the desired state to the actual state with apply.
func (m *Manager) AllResources(bd *fleet.BundleDeployment) (*helmdeployer.Resources, error) {
resources, err := m.deployer.Resources(bd.Name, bd.Status.Release)
if err != nil {
return nil, nil
}
plan, err := m.plan(bd, resources.DefaultNamespace, resources.Objects...)
if err != nil {
return nil, err
}
for gvk, keys := range plan.Delete {
for _, key := range keys {
u := &unstructured.Unstructured{}
u.SetGroupVersionKind(gvk)
u.SetNamespace(key.Namespace)
u.SetName(key.Name)
resources.Objects = append(resources.Objects, u)
}
}
return resources, nil
}
// Deploy the bundle deployment, i.e. with helmdeployer.
// This loads the manifest and the contents from the upstream cluster.
func (m *Manager) Deploy(bd *fleet.BundleDeployment) (string, error) {
if bd.Spec.DeploymentID == bd.Status.AppliedDeploymentID {
if ok, err := m.deployer.EnsureInstalled(bd.Name, bd.Status.Release); err != nil {
return "", err
} else if ok {
return bd.Status.Release, nil
}
}
manifestID, _ := kv.Split(bd.Spec.DeploymentID, ":")
manifest, err := m.lookup.Get(manifestID)
if err != nil {
return "", err
}
manifest.Commit = bd.Labels["fleet.cattle.io/commit"]
resource, err := m.deployer.Deploy(bd.Name, manifest, bd.Spec.Options)
if err != nil {
return "", err
}
return resource.ID, nil
}