-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathfeatures.go
166 lines (153 loc) · 5.16 KB
/
features.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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package main
import (
"fmt"
"strings"
"github.com/subpop/go-log"
"github.com/urfave/cli/v2"
)
// RhcFeature manages optional features of rhc.
type RhcFeature struct {
// ID is an identifier of the feature.
ID string
// Description is human-readable description of the feature.
Description string
// Enabled represents the state of feature
Enabled bool
// Reason for disabling feature
Reason string
// Requires is a list of IDs of other features that are required for this feature. RhcFeature
// dependencies are not resolved.
Requires []*RhcFeature
// EnableFunc is callback function, and it is called when the feature should transition
// into enabled state.
EnableFunc func(ctx *cli.Context) error
// DisableFunc is also callback function, and it is called when the feature should transition
// into disabled state.
DisableFunc func(ctx *cli.Context) error
}
func (f *RhcFeature) String() string {
return fmt.Sprintf("Feature{ID:%s}", f.ID)
}
// KnownFeatures is a sorted list of features, ordered from least to the most dependent.
var KnownFeatures = []*RhcFeature{
&ContentFeature,
&AnalyticsFeature,
&ManagementFeature,
}
// listKnownFeatureIds is helper function, and it returns the list of IDs of known feature
func listKnownFeatureIds() []string {
var ids []string
for _, feature := range KnownFeatures {
ids = append(ids, feature.ID)
}
return ids
}
// ContentFeature allows to enable/disable content provided by Red Hat. It is
// typically set of RPM repositories generated in /etc/yum.repos.d/redhat.repo
var ContentFeature = RhcFeature{
ID: "content",
Requires: []*RhcFeature{},
Enabled: func() bool { return true }(),
Description: "Get access to RHEL content",
EnableFunc: func(ctx *cli.Context) error {
log.Debug("enabling 'content' feature not implemented")
return nil
},
DisableFunc: func(ctx *cli.Context) error {
log.Debug("disabling 'content' feature not implemented")
return nil
},
}
// AnalyticsFeature allows to enable/disable collecting data for Red Hat Insights
var AnalyticsFeature = RhcFeature{
ID: "analytics",
Requires: []*RhcFeature{},
Enabled: func() bool { return true }(),
Description: "Enable data collection for Red Hat Insights",
EnableFunc: func(ctx *cli.Context) error {
log.Debug("enabling 'analytics' feature not implemented")
return nil
},
DisableFunc: func(ctx *cli.Context) error {
log.Debug("disabling 'analytics' feature not implemented")
return nil
},
}
// ManagementFeature allows to enable/disable remote management of the host
// using yggdrasil service and various workers
var ManagementFeature = RhcFeature{
ID: "remote-management",
Requires: []*RhcFeature{&ContentFeature, &AnalyticsFeature},
Enabled: func() bool { return true }(),
Description: "Remote management",
EnableFunc: func(ctx *cli.Context) error {
log.Debug("enabling 'management' feature not implemented")
return nil
},
DisableFunc: func(ctx *cli.Context) error {
log.Debug("disabling 'management' feature not implemented")
return nil
},
}
// checkFeatureInput checks input of enabled and disabled features
func checkFeatureInput(enabledFeaturesIDs *[]string, disabledFeaturesIDs *[]string) error {
// First check disabled features: check only correctness of IDs
for _, featureId := range *disabledFeaturesIDs {
isKnown := false
var disabledFeature *RhcFeature = nil
for _, rhcFeature := range KnownFeatures {
if featureId == rhcFeature.ID {
disabledFeature = rhcFeature
isKnown = true
break
}
}
if !isKnown {
supportedIds := listKnownFeatureIds()
hint := strings.Join(supportedIds, ",")
return fmt.Errorf("cannot disable feature \"%s\": no such feature exists (%s)", featureId, hint)
}
disabledFeature.Enabled = false
}
// Then check enabled features, and it is more tricky, because:
// 1) you cannot enable feature, which was already disabled
// 2) you cannot enable feature, which depends on disabled feature
for _, featureId := range *enabledFeaturesIDs {
isKnown := false
var enabledFeature *RhcFeature = nil
for _, rhcFeature := range KnownFeatures {
if featureId == rhcFeature.ID {
enabledFeature = rhcFeature
isKnown = true
break
}
}
if !isKnown {
supportedIds := listKnownFeatureIds()
hint := strings.Join(supportedIds, ",")
return fmt.Errorf("cannot enable feature \"%s\": no such feature exists (%s)", featureId, hint)
}
for _, disabledFeatureId := range *disabledFeaturesIDs {
if featureId == disabledFeatureId {
return fmt.Errorf("cannot enable feature: \"%s\": feature \"%s\" explicitly disabled",
featureId, disabledFeatureId)
}
for _, requiredFeature := range enabledFeature.Requires {
if requiredFeature.ID == disabledFeatureId {
return fmt.Errorf("cannot enable feature: \"%s\": required feature \"%s\" explicitly disabled",
enabledFeature.ID, disabledFeatureId)
}
}
}
enabledFeature.Enabled = true
}
for _, feature := range KnownFeatures {
for _, requiredFeature := range feature.Requires {
if !requiredFeature.Enabled {
feature.Enabled = false
feature.Reason = fmt.Sprintf("required feature \"%s\" is disabled", requiredFeature.ID)
}
}
}
return nil
}