github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/cli/external_ca.go (about)

     1  package cli
     2  
     3  import (
     4  	"encoding/csv"
     5  	"errors"
     6  	"fmt"
     7  	"strings"
     8  
     9  	"github.com/docker/swarmkit/api"
    10  )
    11  
    12  // ExternalCAOpt is a Value type for parsing external CA specifications.
    13  type ExternalCAOpt struct {
    14  	values []*api.ExternalCA
    15  }
    16  
    17  // Set parses an external CA option.
    18  func (m *ExternalCAOpt) Set(value string) error {
    19  	parsed, err := parseExternalCA(value)
    20  	if err != nil {
    21  		return err
    22  	}
    23  
    24  	m.values = append(m.values, parsed)
    25  	return nil
    26  }
    27  
    28  // Type returns the type of this option.
    29  func (m *ExternalCAOpt) Type() string {
    30  	return "external-ca"
    31  }
    32  
    33  // String returns a string repr of this option.
    34  func (m *ExternalCAOpt) String() string {
    35  	externalCAs := []string{}
    36  	for _, externalCA := range m.values {
    37  		repr := fmt.Sprintf("%s: %s", externalCA.Protocol, externalCA.URL)
    38  		externalCAs = append(externalCAs, repr)
    39  	}
    40  	return strings.Join(externalCAs, ", ")
    41  }
    42  
    43  // Value returns the external CAs
    44  func (m *ExternalCAOpt) Value() []*api.ExternalCA {
    45  	return m.values
    46  }
    47  
    48  // parseExternalCA parses an external CA specification from the command line,
    49  // such as protocol=cfssl,url=https://example.com.
    50  func parseExternalCA(caSpec string) (*api.ExternalCA, error) {
    51  	csvReader := csv.NewReader(strings.NewReader(caSpec))
    52  	fields, err := csvReader.Read()
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	externalCA := api.ExternalCA{
    58  		Options: make(map[string]string),
    59  	}
    60  
    61  	var (
    62  		hasProtocol bool
    63  		hasURL      bool
    64  	)
    65  
    66  	for _, field := range fields {
    67  		parts := strings.SplitN(field, "=", 2)
    68  
    69  		if len(parts) != 2 {
    70  			return nil, fmt.Errorf("invalid field '%s' must be a key=value pair", field)
    71  		}
    72  
    73  		key, value := parts[0], parts[1]
    74  
    75  		switch strings.ToLower(key) {
    76  		case "protocol":
    77  			hasProtocol = true
    78  			if strings.ToLower(value) == "cfssl" {
    79  				externalCA.Protocol = api.ExternalCA_CAProtocolCFSSL
    80  			} else {
    81  				return nil, fmt.Errorf("unrecognized external CA protocol %s", value)
    82  			}
    83  		case "url":
    84  			hasURL = true
    85  			externalCA.URL = value
    86  		default:
    87  			externalCA.Options[key] = value
    88  		}
    89  	}
    90  
    91  	if !hasProtocol {
    92  		return nil, errors.New("the external-ca option needs a protocol= parameter")
    93  	}
    94  	if !hasURL {
    95  		return nil, errors.New("the external-ca option needs a url= parameter")
    96  	}
    97  
    98  	return &externalCA, nil
    99  }