mirror of
https://github.com/k3s-io/k3s.git
synced 2024-06-07 19:41:36 +00:00
Add cert rotation command (#4495)
* Add cert rotation command Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * add function to check for dynamic listener file Signed-off-by: Brian Downs <brian.downs@gmail.com> * Add dynamiclistener cert rotation support Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * fixes to the cert rotation Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * fix ci tests Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * fixes to certificate rotation command Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> * more fixes Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com> Co-authored-by: Brian Downs <brian.downs@gmail.com>
This commit is contained in:
parent
1e6e4db2bc
commit
77fd3e99ec
27
cmd/cert/main.go
Normal file
27
cmd/cert/main.go
Normal file
@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"github.com/rancher/k3s/pkg/cli/cert"
|
||||
"github.com/rancher/k3s/pkg/cli/cmds"
|
||||
"github.com/rancher/k3s/pkg/configfilearg"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := cmds.NewApp()
|
||||
app.Commands = []cli.Command{
|
||||
cmds.NewCertCommand(
|
||||
cmds.NewCertSubcommands(
|
||||
cert.Run),
|
||||
),
|
||||
}
|
||||
|
||||
if err := app.Run(configfilearg.MustParse(os.Args)); err != nil && !errors.Is(err, context.Canceled) {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
}
|
@ -35,6 +35,7 @@ func main() {
|
||||
}
|
||||
|
||||
etcdsnapshotCommand := internalCLIAction(version.Program+"-"+cmds.EtcdSnapshotCommand, dataDir, os.Args)
|
||||
certCommand := internalCLIAction(version.Program+"-"+cmds.CertCommand, dataDir, os.Args)
|
||||
|
||||
// Handle subcommand invocation (k3s server, k3s crictl, etc)
|
||||
app := cmds.NewApp()
|
||||
@ -52,6 +53,10 @@ func main() {
|
||||
etcdsnapshotCommand,
|
||||
etcdsnapshotCommand),
|
||||
),
|
||||
cmds.NewCertCommand(
|
||||
cmds.NewCertSubcommands(
|
||||
certCommand),
|
||||
),
|
||||
}
|
||||
|
||||
if err := app.Run(os.Args); err != nil && !errors.Is(err, context.Canceled) {
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
crictl2 "github.com/kubernetes-sigs/cri-tools/cmd/crictl"
|
||||
"github.com/rancher/k3s/pkg/cli/agent"
|
||||
"github.com/rancher/k3s/pkg/cli/cert"
|
||||
"github.com/rancher/k3s/pkg/cli/cmds"
|
||||
"github.com/rancher/k3s/pkg/cli/crictl"
|
||||
"github.com/rancher/k3s/pkg/cli/ctr"
|
||||
@ -52,6 +53,10 @@ func main() {
|
||||
etcdsnapshot.Prune,
|
||||
etcdsnapshot.Run),
|
||||
),
|
||||
cmds.NewCertCommand(
|
||||
cmds.NewCertSubcommands(
|
||||
cert.Run),
|
||||
),
|
||||
}
|
||||
|
||||
if err := app.Run(configfilearg.MustParse(os.Args)); err != nil && !errors.Is(err, context.Canceled) {
|
||||
|
3
go.mod
3
go.mod
@ -103,9 +103,10 @@ require (
|
||||
// LOOK TO scripts/download FOR THE VERSION OF runc THAT WE ARE BUILDING/SHIPPING
|
||||
github.com/opencontainers/runc v1.0.2
|
||||
github.com/opencontainers/selinux v1.8.2
|
||||
github.com/otiai10/copy v1.6.0
|
||||
github.com/pierrec/lz4 v2.6.0+incompatible
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/rancher/dynamiclistener v0.2.6
|
||||
github.com/rancher/dynamiclistener v0.2.7
|
||||
github.com/rancher/lasso v0.0.0-20210616224652-fc3ebd901c08
|
||||
github.com/rancher/remotedialer v0.2.0
|
||||
github.com/rancher/wharfie v0.3.4
|
||||
|
11
go.sum
11
go.sum
@ -808,6 +808,13 @@ github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3
|
||||
github.com/opencontainers/selinux v1.8.2 h1:c4ca10UMgRcvZ6h0K4HtS15UaVSBEaE+iln2LVpAuGc=
|
||||
github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/otiai10/copy v1.6.0 h1:IinKAryFFuPONZ7cm6T6E2QX/vcJwSnlaA5lfoaXIiQ=
|
||||
github.com/otiai10/copy v1.6.0/go.mod h1:XWfuS3CrI0R6IE0FbgHsEazaXO8G0LpMp9o8tos0x4E=
|
||||
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
|
||||
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
|
||||
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
|
||||
github.com/otiai10/mint v1.3.2 h1:VYWnrP5fXmz1MXvjuUvcBrXSjGE6xjON+axB/UrpO3E=
|
||||
github.com/otiai10/mint v1.3.2/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/paulmach/orb v0.1.3/go.mod h1:VFlX/8C+IQ1p6FTRRKzKoOPJnvEtA5G0Veuqwbu//Vk=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
@ -863,8 +870,8 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d/go.mod h1:7DPO4domFU579Ga6E61sB9VFNaniPVwJP5C4bBCu3wA=
|
||||
github.com/quobyte/api v0.1.8/go.mod h1:jL7lIHrmqQ7yh05OJ+eEEdHr0u/kmT1Ff9iHd+4H6VI=
|
||||
github.com/rancher/dynamiclistener v0.2.6 h1:qcNhQQOidheum5K6mtLxDTJQMTWKm1zm/PjZ5x0xV7A=
|
||||
github.com/rancher/dynamiclistener v0.2.6/go.mod h1:iXFvJLvLjmTzEJBrLFZl9UaMfDLOhv6fHp9fHQRlHGg=
|
||||
github.com/rancher/dynamiclistener v0.2.7 h1:4FTlQtmHO6cY/g4XtGNAZTTxJYEdwn7VgtunX06NFjQ=
|
||||
github.com/rancher/dynamiclistener v0.2.7/go.mod h1:iXFvJLvLjmTzEJBrLFZl9UaMfDLOhv6fHp9fHQRlHGg=
|
||||
github.com/rancher/lasso v0.0.0-20210616224652-fc3ebd901c08 h1:NxR8Fh0eE7/5/5Zvlog9B5NVjWKqBSb1WYMUF7/IE5c=
|
||||
github.com/rancher/lasso v0.0.0-20210616224652-fc3ebd901c08/go.mod h1:9qZd/S8DqWzfKtjKGgSoHqGEByYmUE3qRaBaaAHwfEM=
|
||||
github.com/rancher/remotedialer v0.2.0 h1:xD7t3K6JYwTdAsxmGtTHQMkEkFgKouQ1foLxVW424Dc=
|
||||
|
5
main.go
5
main.go
@ -12,6 +12,7 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/rancher/k3s/pkg/cli/agent"
|
||||
"github.com/rancher/k3s/pkg/cli/cert"
|
||||
"github.com/rancher/k3s/pkg/cli/cmds"
|
||||
"github.com/rancher/k3s/pkg/cli/crictl"
|
||||
"github.com/rancher/k3s/pkg/cli/etcdsnapshot"
|
||||
@ -36,6 +37,10 @@ func main() {
|
||||
etcdsnapshot.Prune,
|
||||
etcdsnapshot.Run),
|
||||
),
|
||||
cmds.NewCertCommand(
|
||||
cmds.NewCertSubcommands(
|
||||
cert.Run),
|
||||
),
|
||||
}
|
||||
|
||||
if err := app.Run(configfilearg.MustParse(os.Args)); err != nil && !errors.Is(err, context.Canceled) {
|
||||
|
221
pkg/cli/cert/cert.go
Normal file
221
pkg/cli/cert/cert.go
Normal file
@ -0,0 +1,221 @@
|
||||
package cert
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/erikdubbelboer/gspt"
|
||||
"github.com/otiai10/copy"
|
||||
"github.com/rancher/k3s/pkg/cli/cmds"
|
||||
"github.com/rancher/k3s/pkg/daemons/config"
|
||||
"github.com/rancher/k3s/pkg/daemons/control/deps"
|
||||
"github.com/rancher/k3s/pkg/datadir"
|
||||
"github.com/rancher/k3s/pkg/server"
|
||||
"github.com/rancher/k3s/pkg/version"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
const (
|
||||
adminService = "admin"
|
||||
apiServerService = "api-server"
|
||||
controllerManagerService = "controller-manager"
|
||||
schedulerService = "scheduler"
|
||||
etcdService = "etcd"
|
||||
programControllerService = "-controller"
|
||||
authProxyService = "auth-proxy"
|
||||
cloudControllerService = "cloud-controller"
|
||||
kubeletService = "kubelet"
|
||||
kubeProxyService = "kube-proxy"
|
||||
k3sServerService = "-server"
|
||||
)
|
||||
|
||||
func commandSetup(app *cli.Context, cfg *cmds.Server, sc *server.Config) (string, string, error) {
|
||||
gspt.SetProcTitle(os.Args[0])
|
||||
|
||||
sc.ControlConfig.DataDir = cfg.DataDir
|
||||
sc.ControlConfig.Runtime = &config.ControlRuntime{}
|
||||
dataDir, err := datadir.Resolve(cfg.DataDir)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return filepath.Join(dataDir, "server"), filepath.Join(dataDir, "agent"), err
|
||||
}
|
||||
|
||||
func Run(app *cli.Context) error {
|
||||
if err := cmds.InitLogging(); err != nil {
|
||||
return err
|
||||
}
|
||||
return rotate(app, &cmds.ServerConfig)
|
||||
}
|
||||
|
||||
func rotate(app *cli.Context, cfg *cmds.Server) error {
|
||||
var serverConfig server.Config
|
||||
|
||||
serverDataDir, agentDataDir, err := commandSetup(app, cfg, &serverConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serverConfig.ControlConfig.DataDir = serverDataDir
|
||||
serverConfig.ControlConfig.Runtime = &config.ControlRuntime{}
|
||||
deps.CreateRuntimeCertFiles(&serverConfig.ControlConfig, serverConfig.ControlConfig.Runtime)
|
||||
|
||||
tlsBackupDir, err := backupCertificates(serverDataDir, agentDataDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(cmds.ServicesList) == 0 {
|
||||
// detecting if the service is an agent or server
|
||||
_, err := os.Stat(serverDataDir)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
logrus.Infof("Agent detected, rotating agent certificates")
|
||||
cmds.ServicesList = []string{
|
||||
kubeletService,
|
||||
kubeProxyService,
|
||||
version.Program + programControllerService,
|
||||
}
|
||||
} else {
|
||||
logrus.Infof("Server detected, rotating server certificates")
|
||||
cmds.ServicesList = []string{
|
||||
adminService,
|
||||
etcdService,
|
||||
apiServerService,
|
||||
controllerManagerService,
|
||||
cloudControllerService,
|
||||
schedulerService,
|
||||
version.Program + k3sServerService,
|
||||
version.Program + programControllerService,
|
||||
authProxyService,
|
||||
kubeletService,
|
||||
kubeProxyService,
|
||||
}
|
||||
}
|
||||
}
|
||||
fileList := []string{}
|
||||
for _, service := range cmds.ServicesList {
|
||||
logrus.Infof("Rotating certificates for %s service", service)
|
||||
switch service {
|
||||
case adminService:
|
||||
fileList = append(fileList,
|
||||
serverConfig.ControlConfig.Runtime.ClientAdminCert,
|
||||
serverConfig.ControlConfig.Runtime.ClientAdminKey)
|
||||
case apiServerService:
|
||||
fileList = append(fileList,
|
||||
serverConfig.ControlConfig.Runtime.ClientKubeAPICert,
|
||||
serverConfig.ControlConfig.Runtime.ClientKubeAPIKey,
|
||||
serverConfig.ControlConfig.Runtime.ServingKubeAPICert,
|
||||
serverConfig.ControlConfig.Runtime.ServingKubeAPIKey)
|
||||
case controllerManagerService:
|
||||
fileList = append(fileList,
|
||||
serverConfig.ControlConfig.Runtime.ClientControllerCert,
|
||||
serverConfig.ControlConfig.Runtime.ClientControllerKey)
|
||||
case schedulerService:
|
||||
fileList = append(fileList,
|
||||
serverConfig.ControlConfig.Runtime.ClientSchedulerCert,
|
||||
serverConfig.ControlConfig.Runtime.ClientSchedulerKey)
|
||||
case etcdService:
|
||||
fileList = append(fileList,
|
||||
serverConfig.ControlConfig.Runtime.ClientETCDCert,
|
||||
serverConfig.ControlConfig.Runtime.ClientETCDKey,
|
||||
serverConfig.ControlConfig.Runtime.ServerETCDCert,
|
||||
serverConfig.ControlConfig.Runtime.ServerETCDKey,
|
||||
serverConfig.ControlConfig.Runtime.PeerServerClientETCDCert,
|
||||
serverConfig.ControlConfig.Runtime.PeerServerClientETCDKey)
|
||||
case cloudControllerService:
|
||||
fileList = append(fileList,
|
||||
serverConfig.ControlConfig.Runtime.ClientCloudControllerCert,
|
||||
serverConfig.ControlConfig.Runtime.ClientCloudControllerKey)
|
||||
case version.Program + k3sServerService:
|
||||
dynamicListenerRegenFilePath := filepath.Join(serverDataDir, "tls", "dynamic-cert-regenerate")
|
||||
if err := ioutil.WriteFile(dynamicListenerRegenFilePath, []byte{}, 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
logrus.Infof("Rotating dynamic listener certificate")
|
||||
case version.Program + programControllerService:
|
||||
fileList = append(fileList,
|
||||
serverConfig.ControlConfig.Runtime.ClientK3sControllerCert,
|
||||
serverConfig.ControlConfig.Runtime.ClientK3sControllerKey,
|
||||
filepath.Join(agentDataDir, "client-"+version.Program+"-controller.crt"),
|
||||
filepath.Join(agentDataDir, "client-"+version.Program+"-controller.key"))
|
||||
case authProxyService:
|
||||
fileList = append(fileList,
|
||||
serverConfig.ControlConfig.Runtime.ClientAuthProxyCert,
|
||||
serverConfig.ControlConfig.Runtime.ClientAuthProxyKey)
|
||||
case kubeletService:
|
||||
fileList = append(fileList,
|
||||
serverConfig.ControlConfig.Runtime.ClientKubeletKey,
|
||||
serverConfig.ControlConfig.Runtime.ServingKubeletKey,
|
||||
filepath.Join(agentDataDir, "client-kubelet.crt"),
|
||||
filepath.Join(agentDataDir, "client-kubelet.key"),
|
||||
filepath.Join(agentDataDir, "serving-kubelet.crt"),
|
||||
filepath.Join(agentDataDir, "serving-kubelet.key"))
|
||||
case kubeProxyService:
|
||||
fileList = append(fileList,
|
||||
serverConfig.ControlConfig.Runtime.ClientKubeProxyCert,
|
||||
serverConfig.ControlConfig.Runtime.ClientKubeProxyKey,
|
||||
filepath.Join(agentDataDir, "client-kube-proxy.crt"),
|
||||
filepath.Join(agentDataDir, "client-kube-proxy.key"))
|
||||
default:
|
||||
logrus.Fatalf("%s is not a recognized service", service)
|
||||
}
|
||||
}
|
||||
|
||||
for _, file := range fileList {
|
||||
if err := os.Remove(file); err == nil {
|
||||
logrus.Debugf("file %s is deleted", file)
|
||||
}
|
||||
}
|
||||
logrus.Infof("Successfully backed up certificates for all services to path %s, please restart %s server or agent to rotate certificates", tlsBackupDir, version.Program)
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyFile(src, destDir string) error {
|
||||
_, err := os.Stat(src)
|
||||
if err == nil {
|
||||
input, err := ioutil.ReadFile(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(filepath.Join(destDir, filepath.Base(src)), input, 0644)
|
||||
} else if errors.Is(err, os.ErrNotExist) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func backupCertificates(serverDataDir, agentDataDir string) (string, error) {
|
||||
serverTLSDir := filepath.Join(serverDataDir, "tls")
|
||||
tlsBackupDir := filepath.Join(serverDataDir, "tls-"+strconv.Itoa(int(time.Now().Unix())))
|
||||
|
||||
if _, err := os.Stat(serverTLSDir); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := copy.Copy(serverTLSDir, tlsBackupDir); err != nil {
|
||||
return "", err
|
||||
}
|
||||
agentCerts := []string{
|
||||
filepath.Join(agentDataDir, "client-"+version.Program+"-controller.crt"),
|
||||
filepath.Join(agentDataDir, "client-"+version.Program+"-controller.key"),
|
||||
filepath.Join(agentDataDir, "client-kubelet.crt"),
|
||||
filepath.Join(agentDataDir, "client-kubelet.key"),
|
||||
filepath.Join(agentDataDir, "serving-kubelet.crt"),
|
||||
filepath.Join(agentDataDir, "serving-kubelet.key"),
|
||||
filepath.Join(agentDataDir, "client-kube-proxy.crt"),
|
||||
filepath.Join(agentDataDir, "client-kube-proxy.key"),
|
||||
}
|
||||
for _, cert := range agentCerts {
|
||||
if err := copyFile(cert, tlsBackupDir); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return tlsBackupDir, nil
|
||||
}
|
52
pkg/cli/cmds/certs.go
Normal file
52
pkg/cli/cmds/certs.go
Normal file
@ -0,0 +1,52 @@
|
||||
package cmds
|
||||
|
||||
import (
|
||||
"github.com/rancher/k3s/pkg/version"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
const CertCommand = "certificate"
|
||||
|
||||
var (
|
||||
ServicesList cli.StringSlice
|
||||
CertCommandFlags = []cli.Flag{
|
||||
DebugFlag,
|
||||
ConfigFlag,
|
||||
LogFile,
|
||||
AlsoLogToStderr,
|
||||
cli.StringFlag{
|
||||
Name: "data-dir,d",
|
||||
Usage: "(data) Folder to hold state default /var/lib/rancher/" + version.Program + " or ${HOME}/.rancher/" + version.Program + " if not root",
|
||||
Destination: &ServerConfig.DataDir,
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "service,s",
|
||||
Usage: "List of services to rotate certificates for. Options include (admin, api-server, controller-manager, scheduler, " + version.Program + "-controller, " + version.Program + "-server, cloud-controller, etcd, auth-proxy, kubelet, kube-proxy)",
|
||||
Value: &ServicesList,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func NewCertCommand(subcommands []cli.Command) cli.Command {
|
||||
return cli.Command{
|
||||
Name: CertCommand,
|
||||
Usage: "Certificates management",
|
||||
SkipFlagParsing: false,
|
||||
SkipArgReorder: true,
|
||||
Subcommands: subcommands,
|
||||
Flags: CertCommandFlags,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCertSubcommands(rotate func(ctx *cli.Context) error) []cli.Command {
|
||||
return []cli.Command{
|
||||
{
|
||||
Name: "rotate",
|
||||
Usage: "Certificate rotation",
|
||||
SkipFlagParsing: false,
|
||||
SkipArgReorder: true,
|
||||
Action: rotate,
|
||||
Flags: CertCommandFlags,
|
||||
},
|
||||
}
|
||||
}
|
@ -54,6 +54,15 @@ func (c *Cluster) newListener(ctx context.Context) (net.Listener, http.Handler,
|
||||
MinVersion: c.config.TLSMinVersion,
|
||||
CipherSuites: c.config.TLSCipherSuites,
|
||||
},
|
||||
RegenerateCerts: func() bool {
|
||||
const regenerateDynamicListenerFile = "dynamic-cert-regenerate"
|
||||
dynamicListenerRegenFilePath := filepath.Join(c.config.DataDir, "tls", regenerateDynamicListenerFile)
|
||||
if _, err := os.Stat(dynamicListenerRegenFilePath); err == nil {
|
||||
os.Remove(dynamicListenerRegenFilePath)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -78,6 +78,7 @@ rm -f \
|
||||
bin/containerd-shim-runc-v2 \
|
||||
bin/k3s-server \
|
||||
bin/k3s-etcd-snapshot \
|
||||
bin/k3s-certificate \
|
||||
bin/kubectl \
|
||||
bin/crictl \
|
||||
bin/ctr
|
||||
@ -107,6 +108,7 @@ CGO_ENABLED=1 "${GO}" build -tags "$TAGS" -ldflags "$VERSIONFLAGS $LDFLAGS $STAT
|
||||
ln -s containerd ./bin/k3s-agent
|
||||
ln -s containerd ./bin/k3s-server
|
||||
ln -s containerd ./bin/k3s-etcd-snapshot
|
||||
ln -s containerd ./bin/k3s-certificate
|
||||
ln -s containerd ./bin/kubectl
|
||||
ln -s containerd ./bin/crictl
|
||||
ln -s containerd ./bin/ctr
|
||||
|
@ -7,7 +7,7 @@ cd $(dirname $0)/..
|
||||
|
||||
GO=${GO-go}
|
||||
|
||||
for i in crictl kubectl k3s-agent k3s-server k3s-etcd-snapshot k3s; do
|
||||
for i in crictl kubectl k3s-agent k3s-server k3s-etcd-snapshot k3s-certificate k3s ; do
|
||||
rm -f bin/$i
|
||||
ln -s containerd bin/$i
|
||||
done
|
||||
|
5
vendor/github.com/otiai10/copy/.gitignore
generated
vendored
Normal file
5
vendor/github.com/otiai10/copy/.gitignore
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
test/data.copy
|
||||
coverage.txt
|
||||
vendor
|
||||
.vagrant
|
||||
.idea/
|
21
vendor/github.com/otiai10/copy/LICENSE
generated
vendored
Normal file
21
vendor/github.com/otiai10/copy/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 otiai10
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
62
vendor/github.com/otiai10/copy/README.md
generated
vendored
Normal file
62
vendor/github.com/otiai10/copy/README.md
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
# copy
|
||||
|
||||
[![Go Reference](https://pkg.go.dev/badge/github.com/otiai10/copy.svg)](https://pkg.go.dev/github.com/otiai10/copy)
|
||||
[![Actions Status](https://github.com/otiai10/copy/workflows/Go/badge.svg)](https://github.com/otiai10/copy/actions)
|
||||
[![codecov](https://codecov.io/gh/otiai10/copy/branch/main/graph/badge.svg)](https://codecov.io/gh/otiai10/copy)
|
||||
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/otiai10/copy/blob/main/LICENSE)
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/otiai10/copy)](https://goreportcard.com/report/github.com/otiai10/copy)
|
||||
[![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/otiai10/copy?sort=semver)](https://pkg.go.dev/github.com/otiai10/copy)
|
||||
|
||||
`copy` copies directories recursively.
|
||||
|
||||
# Example Usage
|
||||
|
||||
```go
|
||||
err := Copy("your/directory", "your/directory.copy")
|
||||
```
|
||||
|
||||
# Advanced Usage
|
||||
|
||||
```go
|
||||
// Options specifies optional actions on copying.
|
||||
type Options struct {
|
||||
|
||||
// OnSymlink can specify what to do on symlink
|
||||
OnSymlink func(src string) SymlinkAction
|
||||
|
||||
// OnDirExists can specify what to do when there is a directory already existing in destination.
|
||||
OnDirExists func(src, dest string) DirExistsAction
|
||||
|
||||
// Skip can specify which files should be skipped
|
||||
Skip func(src string) (bool, error)
|
||||
|
||||
// AddPermission to every entities,
|
||||
// NO MORE THAN 0777
|
||||
AddPermission os.FileMode
|
||||
|
||||
// Sync file after copy.
|
||||
// Useful in case when file must be on the disk
|
||||
// (in case crash happens, for example),
|
||||
// at the expense of some performance penalty
|
||||
Sync bool
|
||||
|
||||
// Preserve the atime and the mtime of the entries
|
||||
// On linux we can preserve only up to 1 millisecond accuracy
|
||||
PreserveTimes bool
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
```go
|
||||
// For example...
|
||||
opt := Options{
|
||||
Skip: func(src string) (bool, error) {
|
||||
return strings.HasSuffix(src, ".git"), nil
|
||||
},
|
||||
}
|
||||
err := Copy("your/directory", "your/directory.copy", opt)
|
||||
```
|
||||
|
||||
# Issues
|
||||
|
||||
- https://github.com/otiai10/copy/issues
|
228
vendor/github.com/otiai10/copy/copy.go
generated
vendored
Normal file
228
vendor/github.com/otiai10/copy/copy.go
generated
vendored
Normal file
@ -0,0 +1,228 @@
|
||||
package copy
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// tmpPermissionForDirectory makes the destination directory writable,
|
||||
// so that stuff can be copied recursively even if any original directory is NOT writable.
|
||||
// See https://github.com/otiai10/copy/pull/9 for more information.
|
||||
tmpPermissionForDirectory = os.FileMode(0755)
|
||||
)
|
||||
|
||||
type timespec struct {
|
||||
Mtime time.Time
|
||||
Atime time.Time
|
||||
Ctime time.Time
|
||||
}
|
||||
|
||||
// Copy copies src to dest, doesn't matter if src is a directory or a file.
|
||||
func Copy(src, dest string, opt ...Options) error {
|
||||
info, err := os.Lstat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return switchboard(src, dest, info, assure(src, dest, opt...))
|
||||
}
|
||||
|
||||
// switchboard switches proper copy functions regarding file type, etc...
|
||||
// If there would be anything else here, add a case to this switchboard.
|
||||
func switchboard(src, dest string, info os.FileInfo, opt Options) (err error) {
|
||||
switch {
|
||||
case info.Mode()&os.ModeSymlink != 0:
|
||||
err = onsymlink(src, dest, info, opt)
|
||||
case info.IsDir():
|
||||
err = dcopy(src, dest, info, opt)
|
||||
case info.Mode()&os.ModeNamedPipe != 0:
|
||||
err = pcopy(dest, info)
|
||||
default:
|
||||
err = fcopy(src, dest, info, opt)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// copyNextOrSkip decide if this src should be copied or not.
|
||||
// Because this "copy" could be called recursively,
|
||||
// "info" MUST be given here, NOT nil.
|
||||
func copyNextOrSkip(src, dest string, info os.FileInfo, opt Options) error {
|
||||
skip, err := opt.Skip(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skip {
|
||||
return nil
|
||||
}
|
||||
return switchboard(src, dest, info, opt)
|
||||
}
|
||||
|
||||
// fcopy is for just a file,
|
||||
// with considering existence of parent directory
|
||||
// and file permission.
|
||||
func fcopy(src, dest string, info os.FileInfo, opt Options) (err error) {
|
||||
|
||||
if err = os.MkdirAll(filepath.Dir(dest), os.ModePerm); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
f, err := os.Create(dest)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer fclose(f, &err)
|
||||
|
||||
if err = os.Chmod(f.Name(), info.Mode()|opt.AddPermission); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
s, err := os.Open(src)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer fclose(s, &err)
|
||||
|
||||
var buf []byte = nil
|
||||
var w io.Writer = f
|
||||
// var r io.Reader = s
|
||||
if opt.CopyBufferSize != 0 {
|
||||
buf = make([]byte, opt.CopyBufferSize)
|
||||
// Disable using `ReadFrom` by io.CopyBuffer.
|
||||
// See https://github.com/otiai10/copy/pull/60#discussion_r627320811 for more details.
|
||||
w = struct{ io.Writer }{f}
|
||||
// r = struct{ io.Reader }{s}
|
||||
}
|
||||
if _, err = io.CopyBuffer(w, s, buf); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if opt.Sync {
|
||||
err = f.Sync()
|
||||
}
|
||||
|
||||
if opt.PreserveTimes {
|
||||
return preserveTimes(info, dest)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// dcopy is for a directory,
|
||||
// with scanning contents inside the directory
|
||||
// and pass everything to "copy" recursively.
|
||||
func dcopy(srcdir, destdir string, info os.FileInfo, opt Options) (err error) {
|
||||
|
||||
_, err = os.Stat(destdir)
|
||||
if err == nil && opt.OnDirExists != nil && destdir != opt.intent.dest {
|
||||
switch opt.OnDirExists(srcdir, destdir) {
|
||||
case Replace:
|
||||
if err := os.RemoveAll(destdir); err != nil {
|
||||
return err
|
||||
}
|
||||
case Untouchable:
|
||||
return nil
|
||||
} // case "Merge" is default behaviour. Go through.
|
||||
} else if err != nil && !os.IsNotExist(err) {
|
||||
return err // Unwelcome error type...!
|
||||
}
|
||||
|
||||
originalMode := info.Mode()
|
||||
|
||||
// Make dest dir with 0755 so that everything writable.
|
||||
if err = os.MkdirAll(destdir, tmpPermissionForDirectory); err != nil {
|
||||
return
|
||||
}
|
||||
// Recover dir mode with original one.
|
||||
defer chmod(destdir, originalMode|opt.AddPermission, &err)
|
||||
|
||||
contents, err := ioutil.ReadDir(srcdir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, content := range contents {
|
||||
cs, cd := filepath.Join(srcdir, content.Name()), filepath.Join(destdir, content.Name())
|
||||
|
||||
if err = copyNextOrSkip(cs, cd, content, opt); err != nil {
|
||||
// If any error, exit immediately
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if opt.PreserveTimes {
|
||||
return preserveTimes(info, destdir)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func onsymlink(src, dest string, info os.FileInfo, opt Options) error {
|
||||
switch opt.OnSymlink(src) {
|
||||
case Shallow:
|
||||
return lcopy(src, dest)
|
||||
case Deep:
|
||||
orig, err := os.Readlink(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info, err = os.Lstat(orig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return copyNextOrSkip(orig, dest, info, opt)
|
||||
case Skip:
|
||||
fallthrough
|
||||
default:
|
||||
return nil // do nothing
|
||||
}
|
||||
}
|
||||
|
||||
// lcopy is for a symlink,
|
||||
// with just creating a new symlink by replicating src symlink.
|
||||
func lcopy(src, dest string) error {
|
||||
src, err := os.Readlink(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Symlink(src, dest)
|
||||
}
|
||||
|
||||
// fclose ANYHOW closes file,
|
||||
// with asiging error raised during Close,
|
||||
// BUT respecting the error already reported.
|
||||
func fclose(f *os.File, reported *error) {
|
||||
if err := f.Close(); *reported == nil {
|
||||
*reported = err
|
||||
}
|
||||
}
|
||||
|
||||
// chmod ANYHOW changes file mode,
|
||||
// with asiging error raised during Chmod,
|
||||
// BUT respecting the error already reported.
|
||||
func chmod(dir string, mode os.FileMode, reported *error) {
|
||||
if err := os.Chmod(dir, mode); *reported == nil {
|
||||
*reported = err
|
||||
}
|
||||
}
|
||||
|
||||
// assure Options struct, should be called only once.
|
||||
// All optional values MUST NOT BE nil/zero after assured.
|
||||
func assure(src, dest string, opts ...Options) Options {
|
||||
defopt := getDefaultOptions(src, dest)
|
||||
if len(opts) == 0 {
|
||||
return defopt
|
||||
}
|
||||
if opts[0].OnSymlink == nil {
|
||||
opts[0].OnSymlink = defopt.OnSymlink
|
||||
}
|
||||
if opts[0].Skip == nil {
|
||||
opts[0].Skip = defopt.Skip
|
||||
}
|
||||
opts[0].intent.src = defopt.intent.src
|
||||
opts[0].intent.dest = defopt.intent.dest
|
||||
return opts[0]
|
||||
}
|
17
vendor/github.com/otiai10/copy/copy_namedpipes.go
generated
vendored
Normal file
17
vendor/github.com/otiai10/copy/copy_namedpipes.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
// +build !windows
|
||||
|
||||
package copy
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// pcopy is for just named pipes
|
||||
func pcopy(dest string, info os.FileInfo) error {
|
||||
if err := os.MkdirAll(filepath.Dir(dest), os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
return syscall.Mkfifo(dest, uint32(info.Mode()))
|
||||
}
|
12
vendor/github.com/otiai10/copy/copy_namedpipes_windows.go
generated
vendored
Normal file
12
vendor/github.com/otiai10/copy/copy_namedpipes_windows.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
// +build windows
|
||||
|
||||
package copy
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// pcopy is for just named pipes. Windows doesn't support them
|
||||
func pcopy(dest string, info os.FileInfo) error {
|
||||
return nil
|
||||
}
|
5
vendor/github.com/otiai10/copy/go.mod
generated
vendored
Normal file
5
vendor/github.com/otiai10/copy/go.mod
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
module github.com/otiai10/copy
|
||||
|
||||
go 1.14
|
||||
|
||||
require github.com/otiai10/mint v1.3.2
|
6
vendor/github.com/otiai10/copy/go.sum
generated
vendored
Normal file
6
vendor/github.com/otiai10/copy/go.sum
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
|
||||
github.com/otiai10/curr v1.0.0 h1:TJIWdbX0B+kpNagQrjgq8bCMrbhiuX73M2XwgtDMoOI=
|
||||
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
|
||||
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
|
||||
github.com/otiai10/mint v1.3.2 h1:VYWnrP5fXmz1MXvjuUvcBrXSjGE6xjON+axB/UrpO3E=
|
||||
github.com/otiai10/mint v1.3.2/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
|
86
vendor/github.com/otiai10/copy/options.go
generated
vendored
Normal file
86
vendor/github.com/otiai10/copy/options.go
generated
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
package copy
|
||||
|
||||
import "os"
|
||||
|
||||
// Options specifies optional actions on copying.
|
||||
type Options struct {
|
||||
|
||||
// OnSymlink can specify what to do on symlink
|
||||
OnSymlink func(src string) SymlinkAction
|
||||
|
||||
// OnDirExists can specify what to do when there is a directory already existing in destination.
|
||||
OnDirExists func(src, dest string) DirExistsAction
|
||||
|
||||
// Skip can specify which files should be skipped
|
||||
Skip func(src string) (bool, error)
|
||||
|
||||
// AddPermission to every entities,
|
||||
// NO MORE THAN 0777
|
||||
AddPermission os.FileMode
|
||||
|
||||
// Sync file after copy.
|
||||
// Useful in case when file must be on the disk
|
||||
// (in case crash happens, for example),
|
||||
// at the expense of some performance penalty
|
||||
Sync bool
|
||||
|
||||
// Preserve the atime and the mtime of the entries.
|
||||
// On linux we can preserve only up to 1 millisecond accuracy.
|
||||
PreserveTimes bool
|
||||
|
||||
// The byte size of the buffer to use for copying files.
|
||||
// If zero, the internal default buffer of 32KB is used.
|
||||
// See https://golang.org/pkg/io/#CopyBuffer for more information.
|
||||
CopyBufferSize uint
|
||||
|
||||
intent struct {
|
||||
src string
|
||||
dest string
|
||||
}
|
||||
}
|
||||
|
||||
// SymlinkAction represents what to do on symlink.
|
||||
type SymlinkAction int
|
||||
|
||||
const (
|
||||
// Deep creates hard-copy of contents.
|
||||
Deep SymlinkAction = iota
|
||||
// Shallow creates new symlink to the dest of symlink.
|
||||
Shallow
|
||||
// Skip does nothing with symlink.
|
||||
Skip
|
||||
)
|
||||
|
||||
// DirExistsAction represents what to do on dest dir.
|
||||
type DirExistsAction int
|
||||
|
||||
const (
|
||||
// Merge preserves or overwrites existing files under the dir (default behavior).
|
||||
Merge DirExistsAction = iota
|
||||
// Replace deletes all contents under the dir and copy src files.
|
||||
Replace
|
||||
// Untouchable does nothing for the dir, and leaves it as it is.
|
||||
Untouchable
|
||||
)
|
||||
|
||||
// getDefaultOptions provides default options,
|
||||
// which would be modified by usage-side.
|
||||
func getDefaultOptions(src, dest string) Options {
|
||||
return Options{
|
||||
OnSymlink: func(string) SymlinkAction {
|
||||
return Shallow // Do shallow copy
|
||||
},
|
||||
OnDirExists: nil, // Default behavior is "Merge".
|
||||
Skip: func(string) (bool, error) {
|
||||
return false, nil // Don't skip
|
||||
},
|
||||
AddPermission: 0, // Add nothing
|
||||
Sync: false, // Do not sync
|
||||
PreserveTimes: false, // Do not preserve the modification time
|
||||
CopyBufferSize: 0, // Do not specify, use default bufsize (32*1024)
|
||||
intent: struct {
|
||||
src string
|
||||
dest string
|
||||
}{src, dest},
|
||||
}
|
||||
}
|
11
vendor/github.com/otiai10/copy/preserve_times.go
generated
vendored
Normal file
11
vendor/github.com/otiai10/copy/preserve_times.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
package copy
|
||||
|
||||
import "os"
|
||||
|
||||
func preserveTimes(srcinfo os.FileInfo, dest string) error {
|
||||
spec := getTimeSpec(srcinfo)
|
||||
if err := os.Chtimes(dest, spec.Atime, spec.Mtime); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
21
vendor/github.com/otiai10/copy/stat_times.go
generated
vendored
Normal file
21
vendor/github.com/otiai10/copy/stat_times.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
// +build !windows,!darwin,!freebsd
|
||||
|
||||
// TODO: add more runtimes
|
||||
|
||||
package copy
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func getTimeSpec(info os.FileInfo) timespec {
|
||||
stat := info.Sys().(*syscall.Stat_t)
|
||||
times := timespec{
|
||||
Mtime: info.ModTime(),
|
||||
Atime: time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec)),
|
||||
Ctime: time.Unix(int64(stat.Ctim.Sec), int64(stat.Ctim.Nsec)),
|
||||
}
|
||||
return times
|
||||
}
|
19
vendor/github.com/otiai10/copy/stat_times_darwin.go
generated
vendored
Normal file
19
vendor/github.com/otiai10/copy/stat_times_darwin.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// +build darwin
|
||||
|
||||
package copy
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func getTimeSpec(info os.FileInfo) timespec {
|
||||
stat := info.Sys().(*syscall.Stat_t)
|
||||
times := timespec{
|
||||
Mtime: info.ModTime(),
|
||||
Atime: time.Unix(stat.Atimespec.Sec, stat.Atimespec.Nsec),
|
||||
Ctime: time.Unix(stat.Ctimespec.Sec, stat.Ctimespec.Nsec),
|
||||
}
|
||||
return times
|
||||
}
|
19
vendor/github.com/otiai10/copy/stat_times_freebsd.go
generated
vendored
Normal file
19
vendor/github.com/otiai10/copy/stat_times_freebsd.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// +build freebsd
|
||||
|
||||
package copy
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func getTimeSpec(info os.FileInfo) timespec {
|
||||
stat := info.Sys().(*syscall.Stat_t)
|
||||
times := timespec{
|
||||
Mtime: info.ModTime(),
|
||||
Atime: time.Unix(int64(stat.Atimespec.Sec), int64(stat.Atimespec.Nsec)),
|
||||
Ctime: time.Unix(int64(stat.Ctimespec.Sec), int64(stat.Ctimespec.Nsec)),
|
||||
}
|
||||
return times
|
||||
}
|
18
vendor/github.com/otiai10/copy/stat_times_windows.go
generated
vendored
Normal file
18
vendor/github.com/otiai10/copy/stat_times_windows.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
// +build windows
|
||||
|
||||
package copy
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func getTimeSpec(info os.FileInfo) timespec {
|
||||
stat := info.Sys().(*syscall.Win32FileAttributeData)
|
||||
return timespec{
|
||||
Mtime: time.Unix(0, stat.LastWriteTime.Nanoseconds()),
|
||||
Atime: time.Unix(0, stat.LastAccessTime.Nanoseconds()),
|
||||
Ctime: time.Unix(0, stat.CreationTime.Nanoseconds()),
|
||||
}
|
||||
}
|
17
vendor/github.com/otiai10/copy/test_setup.go
generated
vendored
Normal file
17
vendor/github.com/otiai10/copy/test_setup.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
// +build !windows
|
||||
|
||||
package copy
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func setup(m *testing.M) {
|
||||
os.MkdirAll("test/data.copy", os.ModePerm)
|
||||
os.Symlink("test/data/case01", "test/data/case03/case01")
|
||||
os.Chmod("test/data/case07/dir_0555", 0555)
|
||||
os.Chmod("test/data/case07/file_0444", 0444)
|
||||
syscall.Mkfifo("test/data/case11/foo/bar", 0555)
|
||||
}
|
15
vendor/github.com/otiai10/copy/test_setup_windows.go
generated
vendored
Normal file
15
vendor/github.com/otiai10/copy/test_setup_windows.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
// +build windows
|
||||
|
||||
package copy
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func setup(m *testing.M) {
|
||||
os.MkdirAll("test/data.copy", os.ModePerm)
|
||||
os.Symlink("test/data/case01", "test/data/case03/case01")
|
||||
os.Chmod("test/data/case07/dir_0555", 0555)
|
||||
os.Chmod("test/data/case07/file_0444", 0444)
|
||||
}
|
6
vendor/github.com/rancher/dynamiclistener/factory/gen.go
generated
vendored
6
vendor/github.com/rancher/dynamiclistener/factory/gen.go
generated
vendored
@ -119,6 +119,12 @@ func (t *TLS) AddCN(secret *v1.Secret, cn ...string) (*v1.Secret, bool, error) {
|
||||
return t.generateCert(secret, cn...)
|
||||
}
|
||||
|
||||
func (t *TLS) Regenerate(secret *v1.Secret) (*v1.Secret, error) {
|
||||
cns := cns(secret)
|
||||
secret, _, err := t.generateCert(nil, cns...)
|
||||
return secret, err
|
||||
}
|
||||
|
||||
func (t *TLS) generateCert(secret *v1.Secret, cn ...string) (*v1.Secret, bool, error) {
|
||||
secret = secret.DeepCopy()
|
||||
if secret == nil {
|
||||
|
33
vendor/github.com/rancher/dynamiclistener/listener.go
generated
vendored
33
vendor/github.com/rancher/dynamiclistener/listener.go
generated
vendored
@ -27,6 +27,7 @@ type TLSFactory interface {
|
||||
AddCN(secret *v1.Secret, cn ...string) (*v1.Secret, bool, error)
|
||||
Merge(target *v1.Secret, additional *v1.Secret) (*v1.Secret, bool, error)
|
||||
Filter(cn ...string) []string
|
||||
Regenerate(secret *v1.Secret) (*v1.Secret, error)
|
||||
}
|
||||
|
||||
type SetFactory interface {
|
||||
@ -74,11 +75,18 @@ func NewListener(l net.Listener, storage TLSStorage, caCert *x509.Certificate, c
|
||||
setter.SetFactory(dynamicListener.factory)
|
||||
}
|
||||
|
||||
if config.RegenerateCerts != nil && config.RegenerateCerts() {
|
||||
if err := dynamicListener.regenerateCerts(); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if config.ExpirationDaysCheck == 0 {
|
||||
config.ExpirationDaysCheck = 30
|
||||
}
|
||||
|
||||
tlsListener := tls.NewListener(dynamicListener.WrapExpiration(config.ExpirationDaysCheck), dynamicListener.tlsConfig)
|
||||
|
||||
return tlsListener, dynamicListener.cacheHandler(), nil
|
||||
}
|
||||
|
||||
@ -129,6 +137,7 @@ type Config struct {
|
||||
MaxSANs int
|
||||
ExpirationDaysCheck int
|
||||
CloseConnOnCertChange bool
|
||||
RegenerateCerts func() bool
|
||||
FilterCN func(...string) []string
|
||||
}
|
||||
|
||||
@ -180,6 +189,30 @@ func (l *listener) WrapExpiration(days int) net.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
// regenerateCerts regenerates the used certificates and
|
||||
// updates the secret.
|
||||
func (l *listener) regenerateCerts() error {
|
||||
l.Lock()
|
||||
defer l.Unlock()
|
||||
|
||||
secret, err := l.storage.Get()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newSecret, err := l.factory.Regenerate(secret)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := l.storage.Update(newSecret); err != nil {
|
||||
return err
|
||||
}
|
||||
// clear version to force cert reload
|
||||
l.version = ""
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *listener) checkExpiration(days int) error {
|
||||
l.Lock()
|
||||
defer l.Unlock()
|
||||
|
5
vendor/modules.txt
vendored
5
vendor/modules.txt
vendored
@ -942,6 +942,9 @@ github.com/opencontainers/runtime-spec/specs-go
|
||||
github.com/opencontainers/selinux/go-selinux
|
||||
github.com/opencontainers/selinux/go-selinux/label
|
||||
github.com/opencontainers/selinux/pkg/pwalk
|
||||
# github.com/otiai10/copy v1.6.0
|
||||
## explicit
|
||||
github.com/otiai10/copy
|
||||
# github.com/pelletier/go-toml v1.9.3
|
||||
github.com/pelletier/go-toml
|
||||
# github.com/peterbourgon/diskv v2.0.1+incompatible
|
||||
@ -974,7 +977,7 @@ github.com/prometheus/common/model
|
||||
github.com/prometheus/procfs
|
||||
github.com/prometheus/procfs/internal/fs
|
||||
github.com/prometheus/procfs/internal/util
|
||||
# github.com/rancher/dynamiclistener v0.2.6
|
||||
# github.com/rancher/dynamiclistener v0.2.7
|
||||
## explicit
|
||||
github.com/rancher/dynamiclistener
|
||||
github.com/rancher/dynamiclistener/cert
|
||||
|
Loading…
Reference in New Issue
Block a user