1 package describe
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7
8 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
9 "github.com/devfile/library/v2/pkg/devfile/generator"
10 "github.com/devfile/library/v2/pkg/devfile/parser"
11 "github.com/devfile/library/v2/pkg/devfile/parser/data/v2/common"
12 "k8s.io/klog"
13
14 "github.com/redhat-developer/odo/pkg/api"
15 "github.com/redhat-developer/odo/pkg/component"
16 "github.com/redhat-developer/odo/pkg/kclient"
17 "github.com/redhat-developer/odo/pkg/log"
18 clierrors "github.com/redhat-developer/odo/pkg/odo/cli/errors"
19 "github.com/redhat-developer/odo/pkg/odo/cli/feature"
20 "github.com/redhat-developer/odo/pkg/odo/commonflags"
21 fcontext "github.com/redhat-developer/odo/pkg/odo/commonflags/context"
22 odocontext "github.com/redhat-developer/odo/pkg/odo/context"
23 "github.com/redhat-developer/odo/pkg/podman"
24 "github.com/redhat-developer/odo/pkg/state"
25 )
26
27 type platformDependent interface {
28 GetPlatform() string
29 }
30
31
32 func DescribeDevfileComponent(
33 ctx context.Context,
34 kubeClient kclient.ClientInterface,
35 podmanClient podman.Client,
36 stateClient state.Client,
37 ) (result api.Component, devfile *parser.DevfileObj, err error) {
38 var (
39 devfileObj = odocontext.GetEffectiveDevfileObj(ctx)
40 devfilePath = odocontext.GetDevfilePath(ctx)
41 componentName = odocontext.GetComponentName(ctx)
42 )
43
44 devfileData, err := api.GetDevfileData(*devfileObj)
45 if err != nil {
46 return api.Component{}, nil, err
47 }
48
49 isPlatformFeatureEnabled := feature.IsEnabled(ctx, feature.GenericPlatformFlag)
50 platform := fcontext.GetPlatform(ctx, "")
51 switch platform {
52 case "":
53 if kubeClient == nil {
54 log.Warning(kclient.NewNoConnectionError())
55 }
56 if isPlatformFeatureEnabled && podmanClient == nil {
57 log.Warning(podman.NewPodmanNotFoundError(nil))
58 }
59 case commonflags.PlatformCluster:
60 if kubeClient == nil {
61 return api.Component{}, nil, kclient.NewNoConnectionError()
62 }
63 podmanClient = nil
64 case commonflags.PlatformPodman:
65 if podmanClient == nil {
66 return api.Component{}, nil, podman.NewPodmanNotFoundError(nil)
67 }
68 kubeClient = nil
69 }
70
71
72 allControlPlaneData, err := stateClient.GetAPIServerPorts(ctx)
73 if err != nil {
74 return api.Component{}, nil, err
75 }
76 for i := range allControlPlaneData {
77 if allControlPlaneData[i].Platform == "" {
78 allControlPlaneData[i].Platform = commonflags.PlatformCluster
79 }
80 }
81
82 devControlPlaneData := filterByPlatform(ctx, true, allControlPlaneData)
83
84
85 allFwdPorts, err := stateClient.GetForwardedPorts(ctx)
86 if err != nil {
87 return api.Component{}, nil, err
88 }
89 if isPlatformFeatureEnabled {
90 for i := range allFwdPorts {
91 if allFwdPorts[i].Platform == "" {
92 allFwdPorts[i].Platform = commonflags.PlatformCluster
93 }
94 }
95 }
96 forwardedPorts := filterByPlatform(ctx, isPlatformFeatureEnabled, allFwdPorts)
97
98 runningOn, err := GetRunningOn(ctx, componentName, kubeClient, podmanClient)
99 if err != nil {
100 return api.Component{}, nil, err
101 }
102
103 var ingresses []api.ConnectionData
104 var routes []api.ConnectionData
105 if kubeClient != nil {
106 ingresses, routes, err = component.ListRoutesAndIngresses(kubeClient, componentName, odocontext.GetApplication(ctx))
107 if err != nil {
108 err = clierrors.NewWarning("failed to get ingresses/routes", err)
109
110 }
111 }
112
113 cmp := api.Component{
114 DevfilePath: devfilePath,
115 DevfileData: devfileData,
116 DevControlPlane: devControlPlaneData,
117 DevForwardedPorts: forwardedPorts,
118 RunningIn: api.MergeRunningModes(runningOn),
119 RunningOn: runningOn,
120 ManagedBy: "odo",
121 Ingresses: ingresses,
122 Routes: routes,
123 }
124 if !isPlatformFeatureEnabled {
125
126 cmp.RunningOn = nil
127 }
128 updateWithRemoteSourceLocation(&cmp)
129 return cmp, devfileObj, err
130 }
131
132
133 func DescribeNamedComponent(
134 ctx context.Context,
135 name string,
136 kubeClient kclient.ClientInterface,
137 podmanClient podman.Client,
138 ) (result api.Component, devfileObj *parser.DevfileObj, err error) {
139
140 isPlatformFeatureEnabled := feature.IsEnabled(ctx, feature.GenericPlatformFlag)
141 platform := fcontext.GetPlatform(ctx, "")
142 switch platform {
143 case "":
144 if isPlatformFeatureEnabled {
145
146 if kubeClient == nil {
147 log.Warning(kclient.NewNoConnectionError())
148 }
149 if podmanClient == nil {
150 log.Warning(podman.NewPodmanNotFoundError(nil))
151 }
152 } else {
153 if kubeClient == nil {
154 return api.Component{}, nil, kclient.NewNoConnectionError()
155 }
156 podmanClient = nil
157 }
158 case commonflags.PlatformCluster:
159 if kubeClient == nil {
160 return api.Component{}, nil, kclient.NewNoConnectionError()
161 }
162 podmanClient = nil
163 case commonflags.PlatformPodman:
164 if podmanClient == nil {
165 return api.Component{}, nil, podman.NewPodmanNotFoundError(nil)
166 }
167 kubeClient = nil
168 }
169
170 runningOn, err := GetRunningOn(ctx, name, kubeClient, podmanClient)
171 if err != nil {
172 return api.Component{}, nil, err
173 }
174
175 devfile, err := component.GetDevfileInfo(ctx, kubeClient, podmanClient, name)
176 if err != nil {
177 return api.Component{}, nil, err
178 }
179
180 var ingresses []api.ConnectionData
181 var routes []api.ConnectionData
182 if kubeClient != nil {
183 ingresses, routes, err = component.ListRoutesAndIngresses(kubeClient, name, odocontext.GetApplication(ctx))
184 if err != nil {
185 return api.Component{}, nil, fmt.Errorf("failed to get ingresses/routes: %w", err)
186 }
187 }
188
189 cmp := api.Component{
190 DevfileData: &api.DevfileData{
191 Devfile: devfile.Data,
192 },
193 RunningIn: api.MergeRunningModes(runningOn),
194 RunningOn: runningOn,
195 ManagedBy: "odo",
196 Ingresses: ingresses,
197 Routes: routes,
198 }
199 if !feature.IsEnabled(ctx, feature.GenericPlatformFlag) {
200
201 cmp.RunningOn = nil
202 }
203
204 return cmp, &devfile, nil
205 }
206
207 func GetRunningOn(ctx context.Context, n string, kubeClient kclient.ClientInterface, podmanClient podman.Client) (map[string]api.RunningModes, error) {
208 var runningOn map[string]api.RunningModes
209 runningModesMap, err := component.GetRunningModes(ctx, kubeClient, podmanClient, n)
210 if err != nil {
211 if !errors.As(err, &component.NoComponentFoundError{}) {
212 return nil, err
213 }
214
215 runningModesMap = nil
216 }
217 if runningModesMap != nil {
218 runningOn = make(map[string]api.RunningModes, len(runningModesMap))
219 if kubeClient != nil && runningModesMap[kubeClient] != nil {
220 runningOn[commonflags.PlatformCluster] = runningModesMap[kubeClient]
221 }
222 if podmanClient != nil && runningModesMap[podmanClient] != nil {
223 runningOn[commonflags.PlatformPodman] = runningModesMap[podmanClient]
224 }
225 }
226 return runningOn, nil
227 }
228
229 func filterByPlatform[T platformDependent](ctx context.Context, isFeatEnabled bool, all []T) (result []T) {
230 if !isFeatEnabled {
231 return nil
232 }
233
234 plt := fcontext.GetPlatform(ctx, "")
235 switch plt {
236 case "":
237
238 result = all
239 case commonflags.PlatformCluster:
240 for _, p := range all {
241 if p.GetPlatform() == "" || p.GetPlatform() == commonflags.PlatformCluster {
242 result = append(result, p)
243 }
244 }
245 case commonflags.PlatformPodman:
246 for _, p := range all {
247 if p.GetPlatform() == commonflags.PlatformPodman {
248 result = append(result, p)
249 }
250 }
251 }
252 return result
253 }
254
255 func updateWithRemoteSourceLocation(cmp *api.Component) {
256 components, err := cmp.DevfileData.Devfile.GetComponents(common.DevfileOptions{
257 ComponentOptions: common.ComponentOptions{ComponentType: v1alpha2.ContainerComponentType},
258 })
259 if err != nil {
260 return
261 }
262 for _, comp := range components {
263 if comp.Container.GetMountSources() {
264 if comp.Container.SourceMapping == "" {
265 comp.Container.SourceMapping = generator.DevfileSourceVolumeMount
266 err = cmp.DevfileData.Devfile.UpdateComponent(comp)
267 if err != nil {
268 klog.V(2).Infof("error occurred while updating the component %s; cause: %s", comp.Name, err)
269 }
270 }
271 }
272 }
273 }
274
View as plain text