Update status check endpoint 
[multicloud/k8s.git] / src / k8splugin / plugins / generic / plugin.go
1 /*
2 Copyright 2018 Intel Corporation.
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6     http://www.apache.org/licenses/LICENSE-2.0
7 Unless required by applicable law or agreed to in writing, software
8 distributed under the License is distributed on an "AS IS" BASIS,
9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 See the License for the specific language governing permissions and
11 limitations under the License.
12 */
13
14 package main
15
16 import (
17         "context"
18         "github.com/onap/multicloud-k8s/src/k8splugin/internal/utils"
19         pkgerrors "github.com/pkg/errors"
20         "k8s.io/apimachinery/pkg/api/meta"
21         metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
22         "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
23         "k8s.io/apimachinery/pkg/runtime/schema"
24
25         "github.com/onap/multicloud-k8s/src/k8splugin/internal/config"
26         "github.com/onap/multicloud-k8s/src/k8splugin/internal/helm"
27         "github.com/onap/multicloud-k8s/src/k8splugin/internal/plugin"
28 )
29
30 // Compile time check to see if genericPlugin implements the correct interface
31 var _ plugin.Reference = genericPlugin{}
32
33 // ExportedVariable is what we will look for when calling the generic plugin
34 var ExportedVariable genericPlugin
35
36 type genericPlugin struct {
37 }
38
39 // Create generic object in a specific Kubernetes cluster
40 func (g genericPlugin) Create(yamlFilePath string, namespace string, client plugin.KubernetesConnector) (string, error) {
41         if namespace == "" {
42                 namespace = "default"
43         }
44
45         //Decode the yaml file to create a runtime.Object
46         unstruct := &unstructured.Unstructured{}
47         //Ignore the returned obj as we expect the data in unstruct
48         _, err := utils.DecodeYAML(yamlFilePath, unstruct)
49         if err != nil {
50                 return "", pkgerrors.Wrap(err, "Decode deployment object error")
51         }
52
53         dynClient := client.GetDynamicClient()
54         mapper := client.GetMapper()
55
56         gvk := unstruct.GroupVersionKind()
57         mapping, err := mapper.RESTMapping(schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind}, gvk.Version)
58         if err != nil {
59                 return "", pkgerrors.Wrap(err, "Mapping kind to resource error")
60         }
61
62         //Add the tracking label to all resources created here
63         labels := unstruct.GetLabels()
64         //Check if labels exist for this object
65         if labels == nil {
66                 labels = map[string]string{}
67         }
68         labels[config.GetConfiguration().KubernetesLabelName] = client.GetInstanceID()
69         unstruct.SetLabels(labels)
70
71         // This checks if the resource we are creating has a podSpec in it
72         // Eg: Deployment, StatefulSet, Job etc..
73         // If a PodSpec is found, the label will be added to it too.
74         plugin.TagPodsIfPresent(unstruct, client.GetInstanceID())
75
76         gvr := mapping.Resource
77         var createdObj *unstructured.Unstructured
78
79         switch mapping.Scope.Name() {
80         case meta.RESTScopeNameNamespace:
81                 createdObj, err = dynClient.Resource(gvr).Namespace(namespace).Create(context.TODO(), unstruct, metav1.CreateOptions{})
82         case meta.RESTScopeNameRoot:
83                 createdObj, err = dynClient.Resource(gvr).Create(context.TODO(), unstruct, metav1.CreateOptions{})
84         default:
85                 return "", pkgerrors.New("Got an unknown RESTSCopeName for mapping: " + gvk.String())
86         }
87
88         if err != nil {
89                 return "", pkgerrors.Wrap(err, "Create object error")
90         }
91
92         return createdObj.GetName(), nil
93 }
94
95 // Update deployment object in a specific Kubernetes cluster
96 func (g genericPlugin) Update(yamlFilePath string, namespace string, client plugin.KubernetesConnector) (string, error) {
97         if namespace == "" {
98                 namespace = "default"
99         }
100
101         //Decode the yaml file to create a runtime.Object
102         unstruct := &unstructured.Unstructured{}
103         //Ignore the returned obj as we expect the data in unstruct
104         _, err := utils.DecodeYAML(yamlFilePath, unstruct)
105         if err != nil {
106                 return "", pkgerrors.Wrap(err, "Decode deployment object error")
107         }
108
109         dynClient := client.GetDynamicClient()
110         mapper := client.GetMapper()
111
112         gvk := unstruct.GroupVersionKind()
113         mapping, err := mapper.RESTMapping(schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind}, gvk.Version)
114         if err != nil {
115                 return "", pkgerrors.Wrap(err, "Mapping kind to resource error")
116         }
117
118         //Add the tracking label to all resources created here
119         labels := unstruct.GetLabels()
120         //Check if labels exist for this object
121         if labels == nil {
122                 labels = map[string]string{}
123         }
124         labels[config.GetConfiguration().KubernetesLabelName] = client.GetInstanceID()
125         unstruct.SetLabels(labels)
126
127         // This checks if the resource we are creating has a podSpec in it
128         // Eg: Deployment, StatefulSet, Job etc..
129         // If a PodSpec is found, the label will be added to it too.
130         plugin.TagPodsIfPresent(unstruct, client.GetInstanceID())
131
132         gvr := mapping.Resource
133         var updatedObj *unstructured.Unstructured
134
135         switch mapping.Scope.Name() {
136         case meta.RESTScopeNameNamespace:
137                 updatedObj, err = dynClient.Resource(gvr).Namespace(namespace).Update(context.TODO(), unstruct, metav1.UpdateOptions{})
138         case meta.RESTScopeNameRoot:
139                 updatedObj, err = dynClient.Resource(gvr).Update(context.TODO(), unstruct, metav1.UpdateOptions{})
140         default:
141                 return "", pkgerrors.New("Got an unknown RESTSCopeName for mapping: " + gvk.String())
142         }
143
144         if err != nil {
145                 return "", pkgerrors.Wrap(err, "Update object error")
146         }
147
148         return updatedObj.GetName(), nil
149 }
150
151 // Get an existing resource hosted in a specific Kubernetes cluster
152 func (g genericPlugin) Get(resource helm.KubernetesResource,
153         namespace string, client plugin.KubernetesConnector) (string, error) {
154         if namespace == "" {
155                 namespace = "default"
156         }
157
158         dynClient := client.GetDynamicClient()
159         mapper := client.GetMapper()
160
161         mapping, err := mapper.RESTMapping(schema.GroupKind{
162                 Group: resource.GVK.Group,
163                 Kind:  resource.GVK.Kind,
164         }, resource.GVK.Version)
165         if err != nil {
166                 return "", pkgerrors.Wrap(err, "Mapping kind to resource error")
167         }
168
169         gvr := mapping.Resource
170         opts := metav1.GetOptions{}
171         var unstruct *unstructured.Unstructured
172         switch mapping.Scope.Name() {
173         case meta.RESTScopeNameNamespace:
174                 unstruct, err = dynClient.Resource(gvr).Namespace(namespace).Get(context.TODO(), resource.Name, opts)
175         case meta.RESTScopeNameRoot:
176                 unstruct, err = dynClient.Resource(gvr).Get(context.TODO(), resource.Name, opts)
177         default:
178                 return "", pkgerrors.New("Got an unknown RESTSCopeName for mapping: " + resource.GVK.String())
179         }
180
181         if err != nil {
182                 return "", pkgerrors.Wrap(err, "Delete object error")
183         }
184
185         return unstruct.GetName(), nil
186 }
187
188 // List all existing resources of the GroupVersionKind
189 // TODO: Implement in seperate patch
190 func (g genericPlugin) List(gvk schema.GroupVersionKind, namespace string,
191         client plugin.KubernetesConnector) ([]helm.KubernetesResource, error) {
192
193         var returnData []helm.KubernetesResource
194         return returnData, nil
195 }
196
197 // Delete an existing resource hosted in a specific Kubernetes cluster
198 func (g genericPlugin) Delete(resource helm.KubernetesResource, namespace string, client plugin.KubernetesConnector) error {
199         if namespace == "" {
200                 namespace = "default"
201         }
202
203         dynClient := client.GetDynamicClient()
204         mapper := client.GetMapper()
205
206         mapping, err := mapper.RESTMapping(schema.GroupKind{
207                 Group: resource.GVK.Group,
208                 Kind:  resource.GVK.Kind,
209         }, resource.GVK.Version)
210         if err != nil {
211                 return pkgerrors.Wrap(err, "Mapping kind to resource error")
212         }
213
214         gvr := mapping.Resource
215         deletePolicy := metav1.DeletePropagationBackground
216         opts := metav1.DeleteOptions{
217                 PropagationPolicy: &deletePolicy,
218         }
219
220         switch mapping.Scope.Name() {
221         case meta.RESTScopeNameNamespace:
222                 err = dynClient.Resource(gvr).Namespace(namespace).Delete(context.TODO(), resource.Name, opts)
223         case meta.RESTScopeNameRoot:
224                 err = dynClient.Resource(gvr).Delete(context.TODO(), resource.Name, opts)
225         default:
226                 return pkgerrors.New("Got an unknown RESTSCopeName for mapping: " + resource.GVK.String())
227         }
228
229         if err != nil {
230                 return pkgerrors.Wrap(err, "Delete object error")
231         }
232         return nil
233 }