Shell scripts are now copied to workdir in container and executed from there.
This commit is contained in:
parent
ecaa627551
commit
2df7171d49
@ -1,4 +1,4 @@
|
|||||||
FROM golang:1.21-alpine3.18 AS build_deps
|
FROM golang:1.21-alpine3.19 AS build_deps
|
||||||
|
|
||||||
# Let scripts know we're running in Docker (useful for containerised development)
|
# Let scripts know we're running in Docker (useful for containerised development)
|
||||||
ENV RUNNING_IN_DOCKER true
|
ENV RUNNING_IN_DOCKER true
|
||||||
@ -22,7 +22,7 @@ COPY . .
|
|||||||
|
|
||||||
RUN CGO_ENABLED=0 go build -o webhook -ldflags '-w -extldflags "-static"' .
|
RUN CGO_ENABLED=0 go build -o webhook -ldflags '-w -extldflags "-static"' .
|
||||||
|
|
||||||
FROM alpine:3.18
|
FROM alpine:3.19
|
||||||
|
|
||||||
RUN apk add --no-cache ca-certificates
|
RUN apk add --no-cache ca-certificates
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
appVersion: v0.0.5-alpha.97
|
appVersion: v0.0.5-alpha.106
|
||||||
description: Cert-Manager webhook for sthome
|
description: Cert-Manager webhook for sthome
|
||||||
name: sthome-webhook
|
name: sthome-webhook
|
||||||
version: 0.0.5-alpha.97
|
version: 0.0.5-alpha.106
|
||||||
|
|||||||
@ -62,9 +62,6 @@ spec:
|
|||||||
- name: scriptdir
|
- name: scriptdir
|
||||||
mountPath: /acme
|
mountPath: /acme
|
||||||
readOnly: false
|
readOnly: false
|
||||||
- name: workdir
|
|
||||||
mountPath: /workdir
|
|
||||||
readOnly: false
|
|
||||||
- name: webroot
|
- name: webroot
|
||||||
mountPath: /webroot
|
mountPath: /webroot
|
||||||
readOnly: false
|
readOnly: false
|
||||||
@ -77,9 +74,6 @@ spec:
|
|||||||
- name: scriptdir
|
- name: scriptdir
|
||||||
hostPath:
|
hostPath:
|
||||||
path: {{ .Values.host.scriptdir }}
|
path: {{ .Values.host.scriptdir }}
|
||||||
- name: workdir
|
|
||||||
hostPath:
|
|
||||||
path: {{ .Values.host.workdir }}
|
|
||||||
- name: webroot
|
- name: webroot
|
||||||
hostPath:
|
hostPath:
|
||||||
path: {{ .Values.host.webrootdir }}
|
path: {{ .Values.host.webrootdir }}
|
||||||
|
|||||||
@ -31,7 +31,7 @@ clusterIssuer:
|
|||||||
image:
|
image:
|
||||||
repository: stuurmcp/cert-manager-webhook-sthome
|
repository: stuurmcp/cert-manager-webhook-sthome
|
||||||
#repository: wstat.sthome.net:5000/cert-manager-webhook-sthome
|
#repository: wstat.sthome.net:5000/cert-manager-webhook-sthome
|
||||||
tag: 0.0.5-alpha.97
|
tag: 0.0.5-alpha.106
|
||||||
#pullPolicy should be IfNotPresent. Set to Always for testing purposes
|
#pullPolicy should be IfNotPresent. Set to Always for testing purposes
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
@ -66,10 +66,11 @@ pki:
|
|||||||
servingCertificateDuration: 8760h # 1y
|
servingCertificateDuration: 8760h # 1y
|
||||||
|
|
||||||
host:
|
host:
|
||||||
workdir: /mnt/stpool1/scripts/acme/cert-manager-webhook-sthome
|
|
||||||
scriptdir: /mnt/stpool1/scripts/acme
|
scriptdir: /mnt/stpool1/scripts/acme
|
||||||
webrootdir: /mnt/stpool1/apps/static-web-server
|
webrootdir: /mnt/stpool1/apps/static-web-server
|
||||||
|
|
||||||
|
extraArgs:
|
||||||
|
|
||||||
secret:
|
secret:
|
||||||
accessKey: ""
|
accessKey: ""
|
||||||
secretKey: ""
|
secretKey: ""
|
||||||
|
|||||||
91
main.go
91
main.go
@ -5,14 +5,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
/*
|
|
||||||
"fmt"
|
|
||||||
"k8s.io/client-go/kubernetes"
|
|
||||||
"k8s.io/client-go/rest"
|
|
||||||
"k8s.io/klog/v2"
|
|
||||||
"github.com/cert-manager/cert-manager/pkg/acme/webhook/apis/acme/v1alpha1"
|
|
||||||
"github.com/cert-manager/cert-manager/pkg/issuer/acme/dns/util"
|
|
||||||
*/
|
|
||||||
"github.com/cert-manager/cert-manager/pkg/acme/webhook/cmd"
|
"github.com/cert-manager/cert-manager/pkg/acme/webhook/cmd"
|
||||||
dns "github.com/stuurmcp/cert-manager-webhook-sthome/pkg/dns"
|
dns "github.com/stuurmcp/cert-manager-webhook-sthome/pkg/dns"
|
||||||
)
|
)
|
||||||
@ -32,88 +24,5 @@ func main() {
|
|||||||
}
|
}
|
||||||
cmd.RunWebhookServer(GroupName,
|
cmd.RunWebhookServer(GroupName,
|
||||||
&dns.LocalDNSProviderSolver{},
|
&dns.LocalDNSProviderSolver{},
|
||||||
//&dns.SthomeSolver{},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
type LocalDNSProviderSolver struct {
|
|
||||||
client kubernetes.Interface
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *LocalDNSProviderSolver) Name() string {
|
|
||||||
return dns.ProviderName + "loc"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (loc *LocalDNSProviderSolver) Present(ch *v1alpha1.ChallengeRequest) error {
|
|
||||||
cfg, err := dns.LoadConfig(ch.Config)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
klog.Infof("CZ: Presenting record for %s, type: %s, uid: %s, key: %s, ns: %s, fqdn: %s, zone: %s, allowambcred: %t, cfg.secret: %s, cfg.email: %s, cfg.allowz: %s",
|
|
||||||
ch.DNSName,
|
|
||||||
ch.UID,
|
|
||||||
ch.Type,
|
|
||||||
ch.Key,
|
|
||||||
ch.ResourceNamespace,
|
|
||||||
ch.ResolvedFQDN,
|
|
||||||
ch.ResolvedZone,
|
|
||||||
ch.AllowAmbientCredentials,
|
|
||||||
cfg.APIKeySecretRef.Name,
|
|
||||||
cfg.Email,
|
|
||||||
strings.Join(cfg.AllowedZones, ","),
|
|
||||||
)
|
|
||||||
// TODO: convert shell script to golang
|
|
||||||
localip := dns.GetOutboundIP(dns.Dnsserver_net)
|
|
||||||
success, _ := dns.Execute(
|
|
||||||
dns.Shell,
|
|
||||||
dns.AcmeAuthCmd,
|
|
||||||
"set",
|
|
||||||
ch.DNSName,
|
|
||||||
ch.ResolvedFQDN,
|
|
||||||
ch.Key,
|
|
||||||
"-l",
|
|
||||||
localip,
|
|
||||||
"-v",
|
|
||||||
)
|
|
||||||
klog.Infof("Execute set TXT returned success: %t", success)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (loc *LocalDNSProviderSolver) CleanUp(ch *v1alpha1.ChallengeRequest) error {
|
|
||||||
//domainName := extractDomainName(ch.ResolvedZone)
|
|
||||||
// TODO: add code that deletes a record from the DNS provider's console
|
|
||||||
localip := dns.GetOutboundIP(dns.Dnsserver_net)
|
|
||||||
success, _ := dns.Execute(
|
|
||||||
dns.Shell,
|
|
||||||
dns.AcmeAuthCmd,
|
|
||||||
"unset",
|
|
||||||
ch.DNSName,
|
|
||||||
ch.ResolvedFQDN,
|
|
||||||
ch.Key,
|
|
||||||
"-l",
|
|
||||||
localip,
|
|
||||||
"-v",
|
|
||||||
)
|
|
||||||
klog.Infof("Execute unset TXT returned success: %t", success)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (loc *LocalDNSProviderSolver) Initialize(kubeClientConfig *rest.Config, stopCh <-chan struct{}) error {
|
|
||||||
cl, err := kubernetes.NewForConfig(kubeClientConfig)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get kubernetes client: %w", err)
|
|
||||||
}
|
|
||||||
loc.client = cl
|
|
||||||
klog.InfoS("CZ: Successfully initialised kubernetes client!")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func extractDomainName(zone string) string {
|
|
||||||
authZone, err := util.FindZoneByFqdn(zone, util.RecursiveNameservers)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("could not get zone by fqdn %v", err)
|
|
||||||
return zone
|
|
||||||
}
|
|
||||||
return util.UnFqdn(authZone)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|||||||
@ -15,9 +15,18 @@ const (
|
|||||||
ProviderName = "sthome"
|
ProviderName = "sthome"
|
||||||
bashShell = "/bin/bash"
|
bashShell = "/bin/bash"
|
||||||
zshShell = "/bin/zsh"
|
zshShell = "/bin/zsh"
|
||||||
|
Workdir = "/workdir"
|
||||||
AcmeDir = "/acme"
|
AcmeDir = "/acme"
|
||||||
Shell = bashShell
|
Shell = bashShell
|
||||||
AcmeAuthCmd = AcmeDir + "/acmeauth.sh"
|
|
||||||
|
AuthScript = "acmeauth.sh"
|
||||||
|
DnsUpdScript = "updatedns.sh"
|
||||||
|
KrbConf = "krb5.conf"
|
||||||
|
Keytab = "krb5.keytab"
|
||||||
|
AuthScriptMode = 0744
|
||||||
|
DnsUpdScriptMode = 0744
|
||||||
|
KrbConfMode = 0644
|
||||||
|
KeytabMode = 0644
|
||||||
|
|
||||||
Dnsserver_net = "10.0.0.15"
|
Dnsserver_net = "10.0.0.15"
|
||||||
Dnsserver_lan = "192.168.2.1"
|
Dnsserver_lan = "192.168.2.1"
|
||||||
@ -25,6 +34,10 @@ const (
|
|||||||
Hostserver_lan = "truenas.sthome.lan"
|
Hostserver_lan = "truenas.sthome.lan"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
AcmeAuthCmd = AcmeDir + "/" + AuthScript
|
||||||
|
)
|
||||||
|
|
||||||
// localDNSProviderConfig is a structure that is used to decode into when
|
// localDNSProviderConfig is a structure that is used to decode into when
|
||||||
// solving a DNS01 challenge.
|
// solving a DNS01 challenge.
|
||||||
// This information is provided by cert-manager, and may be a reference to
|
// This information is provided by cert-manager, and may be a reference to
|
||||||
|
|||||||
@ -2,60 +2,14 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Execute(shell string, arg ...string) (bool, error) {
|
|
||||||
var outb, errb bytes.Buffer
|
|
||||||
cmd := exec.Command(shell, arg...)
|
|
||||||
cmd.Dir = AcmeDir
|
|
||||||
cmd.Stdout = &outb
|
|
||||||
cmd.Stderr = &errb
|
|
||||||
klog.Infof("cmd: %s\n", cmd.String())
|
|
||||||
err := cmd.Run()
|
|
||||||
outstr := strings.TrimSuffix(outb.String(), "\n")
|
|
||||||
errstr := strings.TrimSuffix(errb.String(), "\n")
|
|
||||||
klog.Infof("out:\n%s\n", outstr)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("Script returned error:\nerr:\n")
|
|
||||||
klog.Errorf("%s\n============\n", err)
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if errb.String() != "" {
|
|
||||||
klog.Infof("stderr:\n")
|
|
||||||
klog.Errorf("%s\n============\n", errstr)
|
|
||||||
return false, fmt.Errorf("stderr:\n%q", errstr)
|
|
||||||
}
|
|
||||||
klog.Infof("Script returned success\n")
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://blog.kowalczyk.info/article/wOYk/advanced-command-execution-in-go-with-osexec.html
|
|
||||||
func Execute2(shell string, arg ...string) (bool, error) {
|
|
||||||
var stdoutBuf, stderrBuf bytes.Buffer
|
|
||||||
cmd := exec.Command(shell, arg...)
|
|
||||||
cmd.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf)
|
|
||||||
cmd.Stderr = io.MultiWriter(os.Stderr, &stderrBuf)
|
|
||||||
|
|
||||||
err := cmd.Run()
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("Script returned error:\nerr:\n")
|
|
||||||
klog.Errorf("%s\n============\n", err)
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
outStr, errStr := string(stdoutBuf.String()), string(stderrBuf.String())
|
|
||||||
fmt.Printf("\nout:\n%s\nerr:\n%s\n", outStr, errStr)
|
|
||||||
klog.Infof("Script returned success\n")
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CapturingPassThroughWriter is a writer that remembers
|
// CapturingPassThroughWriter is a writer that remembers
|
||||||
// data written to it and passes it to w
|
// data written to it and passes it to w
|
||||||
type CapturingPassThroughWriter struct {
|
type CapturingPassThroughWriter struct {
|
||||||
@ -80,8 +34,10 @@ func (w *CapturingPassThroughWriter) Bytes() []byte {
|
|||||||
return w.buf.Bytes()
|
return w.buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
func Execute3(shell string, arg ...string) (bool, error) {
|
func Execute(shell string, arg ...string) (bool, error) {
|
||||||
var errStdout, errStderr error
|
var errStdout, errStderr error
|
||||||
|
crlf := []byte("\r\n")
|
||||||
|
lf := []byte("\n")
|
||||||
cmd := exec.Command(shell, arg...)
|
cmd := exec.Command(shell, arg...)
|
||||||
stdoutIn, _ := cmd.StdoutPipe()
|
stdoutIn, _ := cmd.StdoutPipe()
|
||||||
stderrIn, _ := cmd.StderrPipe()
|
stderrIn, _ := cmd.StderrPipe()
|
||||||
@ -112,9 +68,10 @@ func Execute3(shell string, arg ...string) (bool, error) {
|
|||||||
}
|
}
|
||||||
//outStr, errStr := string(stdout.Bytes()), string(stderr.Bytes())
|
//outStr, errStr := string(stdout.Bytes()), string(stderr.Bytes())
|
||||||
//fmt.Printf("\nout:\n%s\nerr:\n%s\n", outStr, errStr)
|
//fmt.Printf("\nout:\n%s\nerr:\n%s\n", outStr, errStr)
|
||||||
errStr := string(stderr.Bytes())
|
errb := bytes.TrimSuffix(stderr.Bytes(), crlf)
|
||||||
|
errb = bytes.TrimSuffix(errb, lf)
|
||||||
if stderr != nil {
|
if stderr != nil {
|
||||||
klog.Infof("err:\n%s\n", errStr)
|
klog.Infof("err:\n%s\n", string(errb))
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import (
|
|||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
|
|
||||||
"github.com/cert-manager/cert-manager/pkg/acme/webhook/apis/acme/v1alpha1"
|
"github.com/cert-manager/cert-manager/pkg/acme/webhook/apis/acme/v1alpha1"
|
||||||
//"github.com/cert-manager/cert-manager/pkg/issuer/acme/dns/util"
|
|
||||||
"github.com/stuurmcp/cert-manager-webhook-sthome/pkg/util"
|
"github.com/stuurmcp/cert-manager-webhook-sthome/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -50,9 +49,10 @@ func (loc *LocalDNSProviderSolver) Present(ch *v1alpha1.ChallengeRequest) error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
updateWorkdir()
|
||||||
// TODO: convert shell script to golang
|
// TODO: convert shell script to golang
|
||||||
//localip := GetOutboundIP(Dnsserver_net)
|
//localip := GetOutboundIP(Dnsserver_net)
|
||||||
success, err := Execute3(
|
success, err := Execute(
|
||||||
Shell,
|
Shell,
|
||||||
// "-c",
|
// "-c",
|
||||||
AcmeAuthCmd,
|
AcmeAuthCmd,
|
||||||
@ -81,7 +81,8 @@ func (loc *LocalDNSProviderSolver) Present(ch *v1alpha1.ChallengeRequest) error
|
|||||||
func (loc *LocalDNSProviderSolver) CleanUp(ch *v1alpha1.ChallengeRequest) error {
|
func (loc *LocalDNSProviderSolver) CleanUp(ch *v1alpha1.ChallengeRequest) error {
|
||||||
//domainName := extractDomainName(ch.ResolvedZone)
|
//domainName := extractDomainName(ch.ResolvedZone)
|
||||||
//localip := GetOutboundIP(Dnsserver_net)
|
//localip := GetOutboundIP(Dnsserver_net)
|
||||||
success, err := Execute3(
|
updateWorkdir()
|
||||||
|
success, err := Execute(
|
||||||
Shell,
|
Shell,
|
||||||
// "-c",
|
// "-c",
|
||||||
AcmeAuthCmd,
|
AcmeAuthCmd,
|
||||||
@ -112,7 +113,8 @@ func (loc *LocalDNSProviderSolver) Initialize(kubeClientConfig *rest.Config, sto
|
|||||||
return fmt.Errorf("failed to get kubernetes client: %w", err)
|
return fmt.Errorf("failed to get kubernetes client: %w", err)
|
||||||
}
|
}
|
||||||
loc.client = cl
|
loc.client = cl
|
||||||
klog.InfoS("CZ: Successfully initialised kubernetes client!")
|
setupWorkdir()
|
||||||
|
klog.Infof("webhook \"%s\" started.", ProviderName)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,8 +6,18 @@ package dns
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
extapi "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
extapi "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||||
|
"k8s.io/klog/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
wg sync.WaitGroup // wg is used to wait for the program to finish.
|
||||||
|
mutex sync.Mutex // mutex is used to define a critical section of code.
|
||||||
)
|
)
|
||||||
|
|
||||||
// loadConfig is a small helper function that decodes JSON configuration into
|
// loadConfig is a small helper function that decodes JSON configuration into
|
||||||
@ -25,6 +35,94 @@ func LoadConfig(cfgJSON *extapi.JSON) (LocalDNSProviderConfig, error) {
|
|||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setupWorkdir() {
|
||||||
|
if _, err := os.Stat(Workdir); os.IsNotExist(err) {
|
||||||
|
klog.Infof("Folder \"%s\" does not exist!. Creating it.", Workdir)
|
||||||
|
err = os.Mkdir(Workdir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
copySrcDestDirFile(AcmeDir, Workdir, AuthScript, AuthScriptMode)
|
||||||
|
copySrcDestDirFile(AcmeDir, Workdir, DnsUpdScript, DnsUpdScriptMode)
|
||||||
|
copySrcDestDirFile(AcmeDir, Workdir, KrbConf, KrbConfMode)
|
||||||
|
copySrcDestDirFile(AcmeDir, Workdir, Keytab, KeytabMode)
|
||||||
|
AcmeAuthCmd = Workdir + "/" + AuthScript
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateWorkdir() {
|
||||||
|
wg.Add(4) // Add a count of two, one for each goroutine.
|
||||||
|
|
||||||
|
go updateIfStale(AuthScript, AuthScriptMode)
|
||||||
|
go updateIfStale(DnsUpdScript, DnsUpdScriptMode)
|
||||||
|
go updateIfStale(KrbConf, KrbConfMode)
|
||||||
|
go updateIfStale(Keytab, KeytabMode)
|
||||||
|
|
||||||
|
wg.Wait() // Wait for the goroutines to finish.
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateIfStale(filename string, mode os.FileMode) error {
|
||||||
|
defer wg.Done() // Schedule the call to Done to tell main we are done.
|
||||||
|
mutex.Lock()
|
||||||
|
sourceFile := AcmeDir + "/" + filename
|
||||||
|
destFile := Workdir + "/" + filename
|
||||||
|
result, err := cmpModTime(sourceFile, destFile)
|
||||||
|
if result > 0 {
|
||||||
|
klog.Infof("Updating \"%s\" from \"%s\" folder.", destFile, AcmeDir)
|
||||||
|
err = CopyFile(sourceFile, destFile, mode)
|
||||||
|
}
|
||||||
|
mutex.Unlock()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
func cmpModTime(file1 string, file2 string) (int, error) {
|
||||||
|
// Get the fileinfo
|
||||||
|
fileInfo, err := os.Stat(file1)
|
||||||
|
if err != nil {
|
||||||
|
klog.Fatal(err)
|
||||||
|
}
|
||||||
|
modtime1 := fileInfo.ModTime()
|
||||||
|
fileInfo, err = os.Stat(file2)
|
||||||
|
if err != nil {
|
||||||
|
klog.Fatal(err)
|
||||||
|
}
|
||||||
|
modtime2 := fileInfo.ModTime()
|
||||||
|
diff := modtime1.Sub(modtime2)
|
||||||
|
if diff < (time.Duration(0) * time.Second) {
|
||||||
|
return -1, nil
|
||||||
|
}
|
||||||
|
if diff > (time.Duration(0) * time.Second) {
|
||||||
|
return 1, nil
|
||||||
|
}
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func copySrcDestDirFile(sourcedir string, destdir string, filename string, mode os.FileMode) error {
|
||||||
|
sourceFile := sourcedir + "/" + filename
|
||||||
|
destFile := destdir + "/" + filename
|
||||||
|
return CopyFile(sourceFile, destFile, mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CopyFile(sourceFile string, destFile string, mode os.FileMode) error {
|
||||||
|
source, err := os.Open(sourceFile) //open the source file
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer source.Close()
|
||||||
|
|
||||||
|
destination, err := os.Create(destFile) //create the destination file
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer destination.Close()
|
||||||
|
_, err = io.Copy(destination, source) //copy the contents of source to destination file
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
err = os.Chmod(destFile, mode)
|
||||||
|
klog.Infof("Copied %s to %s.", sourceFile, destFile)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// quote quotes the provide value
|
// quote quotes the provide value
|
||||||
func quote(value string) string {
|
func quote(value string) string {
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
0.0.5-alpha.97
|
0.0.5-alpha.106
|
||||||
20240418-0139
|
20240418-1937
|
||||||
97
|
106
|
||||||
Loading…
Reference in New Issue
Block a user