Merge "mecm-mepm uninstall playbook added"
[ealt-edge.git] / mep / mepserver / mp1 / plan_discover_svc.go
1 /*
2  * Copyright 2020 Huawei Technologies Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package mp1
18
19 import (
20         "context"
21         "net/http"
22         "net/url"
23
24         "github.com/apache/servicecomb-service-center/server/core"
25         "github.com/apache/servicecomb-service-center/server/core/proto"
26
27         "mepserver/mp1/arch/workspace"
28         "mepserver/mp1/models"
29         meputil "mepserver/mp1/util"
30 )
31
32 type DiscoverDecode struct {
33         workspace.TaskBase
34         R           *http.Request   `json:"r,in"`
35         Ctx         context.Context `json:"ctx,out"`
36         QueryParam  url.Values      `json:"queryParam,out"`
37         CoreRequest interface{}     `json:"coreRequest,out"`
38 }
39
40 func (t *DiscoverDecode) OnRequest(data string) workspace.TaskCode {
41         t.Ctx, t.CoreRequest, t.QueryParam = meputil.GetFindParam(t.R)
42         return workspace.TaskFinish
43 }
44
45 type DiscoverService struct {
46         workspace.TaskBase
47         Ctx         context.Context `json:"ctx,in"`
48         QueryParam  url.Values      `json:"queryParam,in"`
49         CoreRequest interface{}     `json:"coreRequest,in"`
50         CoreRsp     interface{}     `json:"coreRsp,out"`
51 }
52
53 func (t *DiscoverService) checkInstanceId(req *proto.FindInstancesRequest) bool {
54         instanceId := req.AppId
55         if instanceId != "default" {
56                 instances := t.CoreRsp.(*proto.FindInstancesResponse).Instances
57                 for _, val := range instances {
58                         if val.ServiceId+val.InstanceId == instanceId {
59                                 return true
60                         }
61                 }
62                 return false
63         }
64         return true
65 }
66
67 func (t *DiscoverService) OnRequest(data string) workspace.TaskCode {
68         req, ok := t.CoreRequest.(*proto.FindInstancesRequest)
69         if !ok {
70                 t.SetFirstErrorCode(SerErrServiceNotFound, "cast to request fail")
71                 return workspace.TaskFinish
72         }
73         if req.ServiceName == "" {
74                 var errFindByKey error
75                 t.CoreRsp, errFindByKey = meputil.FindInstanceByKey(t.QueryParam)
76                 if errFindByKey != nil || t.CoreRsp == nil {
77                         t.SetFirstErrorCode(SerErrServiceNotFound, errFindByKey.Error())
78                         return workspace.TaskFinish
79                 }
80                 if !t.checkInstanceId(req) {
81                         t.SetFirstErrorCode(SerErrServiceNotFound, "instance id not found")
82                 }
83                 return workspace.TaskFinish
84         }
85
86         findInstance, err := core.InstanceAPI.Find(t.Ctx, req)
87         if err != nil {
88                 t.SetFirstErrorCode(SerErrServiceNotFound, err.Error())
89                 return workspace.TaskFinish
90         }
91         if findInstance == nil || len(findInstance.Instances) == 0 {
92                 t.SetFirstErrorCode(SerErrServiceNotFound, "service not found")
93                 return workspace.TaskFinish
94         }
95
96         t.CoreRsp = findInstance
97         return workspace.TaskFinish
98 }
99
100 type ToStrDiscover struct {
101         HttpErrInf *proto.Response `json:"httpErrInf,out"`
102         workspace.TaskBase
103         CoreRsp interface{} `json:"coreRsp,in"`
104         HttpRsp interface{} `json:"httpRsp,out"`
105 }
106
107 func (t *ToStrDiscover) OnRequest(data string) workspace.TaskCode {
108         t.HttpErrInf, t.HttpRsp = mp1CvtSrvDiscover(t.CoreRsp.(*proto.FindInstancesResponse))
109         return workspace.TaskFinish
110 }
111
112 type RspHook struct {
113         R *http.Request `json:"r,in"`
114         workspace.TaskBase
115         Ctx     context.Context `json:"ctx,in"`
116         HttpRsp interface{}     `json:"httpRsp,in"`
117         HookRsp interface{}     `json:"hookRsp,out"`
118 }
119
120 func (t *RspHook) OnRequest(data string) workspace.TaskCode {
121         t.HookRsp = instanceHook(t.Ctx, t.R, t.HttpRsp)
122         return workspace.TaskFinish
123 }
124
125 func instanceHook(ctx context.Context, r *http.Request, rspData interface{}) interface{} {
126         rspBody, ok := rspData.([]*models.ServiceInfo)
127         if !ok {
128                 return rspData
129         }
130
131         if len(rspBody) == 0 {
132                 return rspBody
133         }
134         consumerName := r.Header.Get("X-ConsumerName")
135         if consumerName == "APIGW" {
136                 return rspBody
137         }
138
139         for _, v := range rspBody {
140                 if apihook.APIHook != nil {
141                         info := apihook.APIHook()
142                         if len(info.Addresses) == 0 && len(info.Uris) == 0 {
143                                 return rspBody
144                         }
145                         v.TransportInfo.Endpoint = info
146                 }
147         }
148         return rspBody
149 }
150
151 type SendHttpRsp struct {
152         HttpErrInf *proto.Response `json:"httpErrInf,in"`
153         workspace.TaskBase
154         W       http.ResponseWriter `json:"w,in"`
155         HttpRsp interface{}         `json:"httpRsp,in"`
156 }
157
158 func (t *SendHttpRsp) OnRequest(data string) workspace.TaskCode {
159         errInfo := t.GetSerErrInfo()
160         if errInfo.ErrCode >= int(workspace.TaskFail) {
161                 statusCode, httpBody := t.cvtHttpErrInfo(errInfo)
162                 meputil.HttpErrResponse(t.W, statusCode, httpBody)
163
164                 return workspace.TaskFinish
165         }
166         meputil.WriteResponse(t.W, t.HttpErrInf, t.HttpRsp)
167         return workspace.TaskFinish
168 }
169
170 func (t *SendHttpRsp) cvtHttpErrInfo(errInfo *workspace.SerErrInfo) (int, interface{}) {
171         statusCode := http.StatusBadRequest
172         var httpBody interface{}
173         switch workspace.ErrCode(errInfo.ErrCode) {
174         case SerErrServiceNotFound:
175                 {
176                         //status should return bad request
177                         body := &models.ProblemDetails{
178                                 Title:  "Can not found resource",
179                                 Status: uint32(errInfo.ErrCode),
180                                 Detail: errInfo.Message,
181                         }
182                         httpBody = body
183                 }
184         case SerInstanceNotFound:
185                 {
186                         statusCode = http.StatusNotFound
187                         body := &models.ProblemDetails{
188                                 Title:  "Can not found resource",
189                                 Status: uint32(errInfo.ErrCode),
190                                 Detail: errInfo.Message,
191                         }
192                         httpBody = body
193                 }
194         }
195
196         return statusCode, httpBody
197 }
198
199 func mp1CvtSrvDiscover(findInsResp *proto.FindInstancesResponse) (*proto.Response, []*models.ServiceInfo) {
200         resp := findInsResp.Response
201         if resp != nil && resp.GetCode() != proto.Response_SUCCESS {
202                 return resp, nil
203         }
204         serviceInfos := make([]*models.ServiceInfo, 0, len(findInsResp.Instances))
205         for _, ins := range findInsResp.Instances {
206                 serviceInfo := &models.ServiceInfo{}
207                 serviceInfo.FromServiceInstance(ins)
208                 serviceInfos = append(serviceInfos, serviceInfo)
209         }
210         return resp, serviceInfos
211
212 }