mirror of https://github.com/linkerd/linkerd2.git
176 lines
6.5 KiB
Go
176 lines
6.5 KiB
Go
package cmd
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
"text/template"
|
|
|
|
"github.com/linkerd/linkerd2/cli/install"
|
|
"github.com/linkerd/linkerd2/pkg/k8s"
|
|
"github.com/linkerd/linkerd2/pkg/version"
|
|
log "github.com/sirupsen/logrus"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
type installCNIPluginConfig struct {
|
|
Namespace string
|
|
CNIPluginImage string
|
|
LogLevel string
|
|
InboundPort uint
|
|
OutboundPort uint
|
|
IgnoreInboundPorts string
|
|
IgnoreOutboundPorts string
|
|
ProxyUID int64
|
|
DestCNINetDir string
|
|
DestCNIBinDir string
|
|
CreatedByAnnotation string
|
|
CliVersion string
|
|
}
|
|
|
|
type cniPluginOptions struct {
|
|
linkerdVersion string
|
|
dockerRegistry string
|
|
proxyControlPort uint
|
|
proxyAdminPort uint
|
|
inboundPort uint
|
|
outboundPort uint
|
|
ignoreInboundPorts []uint
|
|
ignoreOutboundPorts []uint
|
|
proxyUID int64
|
|
cniPluginImage string
|
|
logLevel string
|
|
destCNINetDir string
|
|
destCNIBinDir string
|
|
}
|
|
|
|
func newCNIPluginOptions() *cniPluginOptions {
|
|
return &cniPluginOptions{
|
|
linkerdVersion: version.Version,
|
|
dockerRegistry: defaultDockerRegistry,
|
|
proxyControlPort: 4190,
|
|
proxyAdminPort: 4191,
|
|
inboundPort: 4143,
|
|
outboundPort: 4140,
|
|
ignoreInboundPorts: nil,
|
|
ignoreOutboundPorts: nil,
|
|
proxyUID: 2102,
|
|
cniPluginImage: defaultDockerRegistry + "/cni-plugin",
|
|
logLevel: "info",
|
|
destCNINetDir: "/etc/cni/net.d",
|
|
destCNIBinDir: "/opt/cni/bin",
|
|
}
|
|
}
|
|
|
|
func (options *cniPluginOptions) validate() error {
|
|
if !alphaNumDashDot.MatchString(options.linkerdVersion) {
|
|
return fmt.Errorf("%s is not a valid version", options.linkerdVersion)
|
|
}
|
|
|
|
if !alphaNumDashDotSlashColon.MatchString(options.dockerRegistry) {
|
|
return fmt.Errorf("%s is not a valid Docker registry. The url can contain only letters, numbers, dash, dot, slash and colon", options.dockerRegistry)
|
|
}
|
|
|
|
if _, err := log.ParseLevel(options.logLevel); err != nil {
|
|
return fmt.Errorf("--cni-log-level must be one of: panic, fatal, error, warn, info, debug")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (options *cniPluginOptions) taggedCNIPluginImage() string {
|
|
image := registryOverride(options.cniPluginImage, options.dockerRegistry)
|
|
return fmt.Sprintf("%s:%s", image, options.linkerdVersion)
|
|
}
|
|
|
|
func newCmdInstallCNIPlugin() *cobra.Command {
|
|
options := newCNIPluginOptions()
|
|
|
|
cmd := &cobra.Command{
|
|
Use: "install-cni [flags]",
|
|
Short: "Output Kubernetes configs to install Linkerd CNI (experimental)",
|
|
Long: `Output Kubernetes configs to install Linkerd CNI (experimental).
|
|
|
|
This command installs a DaemonSet into the Linkerd control plane. The DaemonSet
|
|
copies the necessary linkerd-cni plugin binaries and configs onto the host. It
|
|
assumes that the 'linkerd install' command will be executed with the
|
|
'--linkerd-cni-enabled' flag. This command needs to be executed before the
|
|
'linkerd install --linkerd-cni-enabled' command.`,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
config, err := validateAndBuildCNIConfig(options)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return renderCNIPlugin(os.Stdout, config)
|
|
},
|
|
}
|
|
|
|
cmd.PersistentFlags().StringVarP(&options.linkerdVersion, "linkerd-version", "v", options.linkerdVersion, "Tag to be used for Linkerd images")
|
|
cmd.PersistentFlags().StringVar(&options.dockerRegistry, "registry", options.dockerRegistry, "Docker registry to pull images from")
|
|
cmd.PersistentFlags().Int64Var(&options.proxyUID, "proxy-uid", options.proxyUID, "Run the proxy under this user ID")
|
|
cmd.PersistentFlags().UintVar(&options.inboundPort, "inbound-port", options.inboundPort, "Proxy port to use for inbound traffic")
|
|
cmd.PersistentFlags().UintVar(&options.outboundPort, "outbound-port", options.outboundPort, "Proxy port to use for outbound traffic")
|
|
cmd.PersistentFlags().UintVar(&options.proxyControlPort, "control-port", options.proxyControlPort, "Proxy port to use for control")
|
|
cmd.PersistentFlags().UintVar(&options.proxyAdminPort, "admin-port", options.proxyAdminPort, "Proxy port to serve metrics on")
|
|
cmd.PersistentFlags().UintSliceVar(&options.ignoreInboundPorts, "skip-inbound-ports", options.ignoreInboundPorts, "Ports that should skip the proxy and send directly to the application")
|
|
cmd.PersistentFlags().UintSliceVar(&options.ignoreOutboundPorts, "skip-outbound-ports", options.ignoreOutboundPorts, "Outbound ports that should skip the proxy")
|
|
cmd.PersistentFlags().StringVar(&options.cniPluginImage, "cni-image", options.cniPluginImage, "Image for the cni-plugin.")
|
|
cmd.PersistentFlags().StringVar(&options.logLevel, "cni-log-level", options.logLevel, "Log level for the cni-plugin.")
|
|
cmd.PersistentFlags().StringVar(&options.destCNINetDir, "dest-cni-net-dir", options.destCNINetDir, "Directory on the host where the CNI configuration will be placed.")
|
|
cmd.PersistentFlags().StringVar(&options.destCNIBinDir, "dest-cni-bin-dir", options.destCNIBinDir, "Directory on the host where the CNI plugin binaries reside.")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func validateAndBuildCNIConfig(options *cniPluginOptions) (*installCNIPluginConfig, error) {
|
|
if err := options.validate(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ignoreInboundPorts := []string{
|
|
fmt.Sprintf("%d", options.proxyControlPort),
|
|
fmt.Sprintf("%d", options.proxyAdminPort),
|
|
}
|
|
for _, p := range options.ignoreInboundPorts {
|
|
ignoreInboundPorts = append(ignoreInboundPorts, fmt.Sprintf("%d", p))
|
|
}
|
|
ignoreOutboundPorts := []string{}
|
|
for _, p := range options.ignoreOutboundPorts {
|
|
ignoreOutboundPorts = append(ignoreOutboundPorts, fmt.Sprintf("%d", p))
|
|
}
|
|
|
|
return &installCNIPluginConfig{
|
|
Namespace: controlPlaneNamespace,
|
|
CNIPluginImage: options.taggedCNIPluginImage(),
|
|
LogLevel: options.logLevel,
|
|
InboundPort: options.inboundPort,
|
|
OutboundPort: options.outboundPort,
|
|
IgnoreInboundPorts: strings.Join(ignoreInboundPorts, ","),
|
|
IgnoreOutboundPorts: strings.Join(ignoreOutboundPorts, ","),
|
|
ProxyUID: options.proxyUID,
|
|
DestCNINetDir: options.destCNINetDir,
|
|
DestCNIBinDir: options.destCNIBinDir,
|
|
CreatedByAnnotation: k8s.CreatedByAnnotation,
|
|
CliVersion: k8s.CreatedByAnnotationValue(),
|
|
}, nil
|
|
}
|
|
|
|
func renderCNIPlugin(w io.Writer, config *installCNIPluginConfig) error {
|
|
template, err := template.New("linkerd-cni").Parse(install.CNITemplate)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
buf := &bytes.Buffer{}
|
|
err = template.Execute(buf, config)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
w.Write(buf.Bytes())
|
|
w.Write([]byte("---\n"))
|
|
|
|
return nil
|
|
}
|