github.com/erda-project/erda-infra@v1.0.9/providers/component-protocol/protocol/protocol.go (about)

     1  // Copyright (c) 2021 Terminus, Inc.
     2  //
     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  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package protocol
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"io/ioutil"
    21  	"strings"
    22  
    23  	"github.com/sirupsen/logrus"
    24  	"gopkg.in/yaml.v3"
    25  
    26  	"github.com/erda-project/erda-infra/pkg/strutil"
    27  	"github.com/erda-project/erda-infra/providers/component-protocol/cptype"
    28  	"github.com/erda-project/erda-infra/providers/component-protocol/utils/cputil"
    29  )
    30  
    31  // defaultProtocols contains all default protocols.
    32  // map key: scenarioKey
    33  // map value: default protocol
    34  var defaultProtocols = make(map[string]cptype.ComponentProtocol)
    35  var defaultProtocolsRaw = make(map[string]string)
    36  
    37  // RegisterDefaultProtocols register protocol contents.
    38  func RegisterDefaultProtocols(protocolYAMLs ...[]byte) {
    39  	for idx, protocolYAML := range protocolYAMLs {
    40  		var p cptype.ComponentProtocol
    41  		if err := yaml.Unmarshal(protocolYAML, &p); err != nil {
    42  			panic(fmt.Errorf("failed to parse protocol yaml, index: %d, err: %v", idx, err))
    43  		}
    44  		if p.Scenario == "" {
    45  			continue
    46  		}
    47  		defaultProtocols[p.Scenario] = p
    48  		if CpPlaceHolderRe.Match(protocolYAML) {
    49  			defaultProtocolsRaw[p.Scenario] = string(protocolYAML)
    50  		}
    51  		logrus.Infof("default protocol registered for scenario: %s", p.Scenario)
    52  	}
    53  }
    54  
    55  // RegisterDefaultProtocolsFromBasePath register default component protocols under base path.
    56  // default path: libs/erda-configs/permission
    57  func RegisterDefaultProtocolsFromBasePath(basePath string) {
    58  	var err error
    59  	defer func() {
    60  		if err != nil {
    61  			logrus.Errorf("failed to register default component protocol, err: %v", err)
    62  			panic(err)
    63  		}
    64  	}()
    65  	rd, err := ioutil.ReadDir(basePath)
    66  	if err != nil {
    67  		return
    68  	}
    69  	for _, fi := range rd {
    70  		if fi.IsDir() {
    71  			fullDir := basePath + "/" + fi.Name()
    72  			RegisterDefaultProtocolsFromBasePath(fullDir)
    73  		} else {
    74  			if fi.Name() != "protocol.yml" && fi.Name() != "protocol.yaml" {
    75  				continue
    76  			}
    77  			fullName := basePath + "/" + fi.Name()
    78  			yamlFile, er := ioutil.ReadFile(fullName)
    79  			if er != nil {
    80  				err = er
    81  				return
    82  			}
    83  			var p cptype.ComponentProtocol
    84  			if er := yaml.Unmarshal(yamlFile, &p); er != nil {
    85  				err = er
    86  				return
    87  			}
    88  			defaultProtocols[p.Scenario] = p
    89  			logrus.Infof("default protocol registered for scenario: %s", p.Scenario)
    90  		}
    91  	}
    92  }
    93  
    94  // getDefaultProtocol get default protocol by scenario.
    95  func getDefaultProtocol(ctx context.Context, scenario string) (cptype.ComponentProtocol, error) {
    96  	rawYamlStr, ok := defaultProtocolsRaw[scenario]
    97  	if !ok {
    98  		// protocol not have cp placeholder
    99  		p, ok := defaultProtocols[scenario]
   100  		if !ok {
   101  			return cptype.ComponentProtocol{}, fmt.Errorf(i18n(ctx, "${default.protocol.not.exist}, ${scenario}: %s", scenario))
   102  		}
   103  		return p, nil
   104  	}
   105  	lang := cputil.Language(ctx)
   106  	tran := ctx.Value(cptype.GlobalInnerKeyCtxSDK).(*cptype.SDK).Tran
   107  	replaced := strutil.ReplaceAllStringSubmatchFunc(CpPlaceHolderRe, rawYamlStr, func(v []string) string {
   108  		if len(v) == 2 && strings.HasPrefix(v[1], I18n+".") {
   109  			key := strings.TrimPrefix(v[1], I18n+".")
   110  			if len(key) > 0 {
   111  				return tran.Text(lang, key)
   112  			}
   113  		}
   114  		return v[0]
   115  	})
   116  	var p cptype.ComponentProtocol
   117  	if err := yaml.Unmarshal([]byte(replaced), &p); err != nil {
   118  		return cptype.ComponentProtocol{}, fmt.Errorf("failed to parse protocol yaml i18n, err: %v", err)
   119  	}
   120  	return p, nil
   121  }
   122  
   123  // getProtoComp .
   124  func getProtoComp(ctx context.Context, p *cptype.ComponentProtocol, compName string) (c *cptype.Component, err error) {
   125  	if p.Components == nil {
   126  		err = fmt.Errorf("empty protocol components")
   127  		return
   128  	}
   129  
   130  	c, ok := p.Components[compName]
   131  	if !ok {
   132  		defaultProtocol, err := getDefaultProtocol(ctx, p.Scenario)
   133  		if err != nil {
   134  			return c, err
   135  		}
   136  		c, ok = defaultProtocol.Components[compName]
   137  		if !ok {
   138  			err = fmt.Errorf("empty component [%s] in default protocol", compName)
   139  		}
   140  		p.Components[compName] = c
   141  		return c, err
   142  	}
   143  	return
   144  }
   145  
   146  // getProtoCompStateValue .
   147  func getProtoCompStateValue(ctx context.Context, p *cptype.ComponentProtocol, compName, sk string) (interface{}, error) {
   148  	c, err := getProtoComp(ctx, p, compName)
   149  	if err != nil {
   150  		return nil, err
   151  	}
   152  	v, err := getCompStateKV(c, sk)
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  	return v, nil
   157  }
   158  
   159  // polishProtocol .
   160  func polishProtocol(req *cptype.ComponentProtocol) {
   161  	if req == nil {
   162  		return
   163  	}
   164  	// polish component name
   165  	for name, component := range req.Components {
   166  		component.Name = name
   167  	}
   168  }