Moved shell.go to its own package
This commit is contained in:
parent
b6cb36ff3e
commit
6b58b5da3c
@ -1,5 +1,5 @@
|
||||
apiVersion: v1
|
||||
appVersion: v0.0.5-alpha.109
|
||||
appVersion: v0.0.5-alpha.110
|
||||
description: Cert-Manager webhook for sthome
|
||||
name: sthome-webhook
|
||||
version: 0.0.5-alpha.109
|
||||
version: 0.0.5-alpha.110
|
||||
|
||||
@ -31,7 +31,7 @@ clusterIssuer:
|
||||
image:
|
||||
repository: stuurmcp/cert-manager-webhook-sthome
|
||||
#repository: wstat.sthome.net:5000/cert-manager-webhook-sthome
|
||||
tag: 0.0.5-alpha.109
|
||||
tag: 0.0.5-alpha.110
|
||||
#pullPolicy should be IfNotPresent. Set to Always for testing purposes
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
|
||||
@ -9,35 +9,16 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
ProviderName = "sthome"
|
||||
SthomeAccessKeyEnv = "STHOME_ACCESS_KEY"
|
||||
SthomeSecretKeyEnv = "STHOME_SECRET_KEY"
|
||||
|
||||
ProviderName = "sthome"
|
||||
bashShell = "/bin/bash"
|
||||
zshShell = "/bin/zsh"
|
||||
Workdir = "/workdir"
|
||||
AcmeDir = "/acme"
|
||||
Shell = bashShell
|
||||
|
||||
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_lan = "192.168.2.1"
|
||||
Hostserver_net = "truenas.sthome.net"
|
||||
Hostserver_lan = "truenas.sthome.lan"
|
||||
)
|
||||
|
||||
var (
|
||||
AcmeAuthCmd = AcmeDir + "/" + AuthScript
|
||||
)
|
||||
|
||||
// localDNSProviderConfig is a structure that is used to decode into when
|
||||
// solving a DNS01 challenge.
|
||||
// This information is provided by cert-manager, and may be a reference to
|
||||
|
||||
@ -1,77 +0,0 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sync"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// CapturingPassThroughWriter is a writer that remembers
|
||||
// data written to it and passes it to w
|
||||
type CapturingPassThroughWriter struct {
|
||||
buf bytes.Buffer
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
// NewCapturingPassThroughWriter creates new CapturingPassThroughWriter
|
||||
func NewCapturingPassThroughWriter(w io.Writer) *CapturingPassThroughWriter {
|
||||
return &CapturingPassThroughWriter{
|
||||
w: w,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *CapturingPassThroughWriter) Write(d []byte) (int, error) {
|
||||
w.buf.Write(d)
|
||||
return w.w.Write(d)
|
||||
}
|
||||
|
||||
// Bytes returns bytes written to the writer
|
||||
func (w *CapturingPassThroughWriter) Bytes() []byte {
|
||||
return w.buf.Bytes()
|
||||
}
|
||||
|
||||
func Execute(shell string, arg ...string) (bool, error) {
|
||||
var errStdout, errStderr error
|
||||
crlf := []byte("\r\n")
|
||||
lf := []byte("\n")
|
||||
cmd := exec.Command(shell, arg...)
|
||||
stdoutIn, _ := cmd.StdoutPipe()
|
||||
stderrIn, _ := cmd.StderrPipe()
|
||||
stdout := NewCapturingPassThroughWriter(os.Stdout)
|
||||
stderr := NewCapturingPassThroughWriter(os.Stderr)
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
klog.Fatalf("cmd.Start() failed with '%s'\n", err)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
|
||||
go func() {
|
||||
_, errStdout = io.Copy(stdout, stdoutIn)
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
_, errStderr = io.Copy(stderr, stderrIn)
|
||||
wg.Wait()
|
||||
|
||||
err = cmd.Wait()
|
||||
if err != nil {
|
||||
klog.Fatalf("cmd.Run() failed with %s\n", err)
|
||||
}
|
||||
if errStdout != nil || errStderr != nil {
|
||||
klog.Fatalf("failed to capture stdout or stderr\n")
|
||||
}
|
||||
//outStr, errStr := string(stdout.Bytes()), string(stderr.Bytes())
|
||||
//fmt.Printf("\nout:\n%s\nerr:\n%s\n", outStr, errStr)
|
||||
errb := bytes.TrimSuffix(stderr.Bytes(), crlf)
|
||||
errb = bytes.TrimSuffix(errb, lf)
|
||||
if errb != nil {
|
||||
klog.Infof("err:\n%s\n", string(errb))
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"github.com/cert-manager/cert-manager/pkg/acme/webhook/apis/acme/v1alpha1"
|
||||
sh "github.com/stuurmcp/cert-manager-webhook-sthome/pkg/shell"
|
||||
"github.com/stuurmcp/cert-manager-webhook-sthome/pkg/util"
|
||||
)
|
||||
|
||||
@ -49,21 +50,10 @@ func (loc *LocalDNSProviderSolver) Present(ch *v1alpha1.ChallengeRequest) error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updateWorkdir()
|
||||
sh.SetupWorkdir()
|
||||
// TODO: convert shell script to golang
|
||||
//localip := GetOutboundIP(Dnsserver_net)
|
||||
success, err := Execute(
|
||||
Shell,
|
||||
// "-c",
|
||||
AcmeAuthCmd,
|
||||
"set",
|
||||
ch.DNSName,
|
||||
ch.ResolvedFQDN,
|
||||
ch.Key,
|
||||
"-l",
|
||||
"\"\"", //localip,
|
||||
//"-v",
|
||||
)
|
||||
success, err := sh.SetChallenge(ch)
|
||||
klog.Infof("Present: Execute set TXT returned success: %t\n", success)
|
||||
err2 := loc.Check(ch.DNSName, ch.Key)
|
||||
if err2 != nil {
|
||||
@ -81,19 +71,7 @@ func (loc *LocalDNSProviderSolver) Present(ch *v1alpha1.ChallengeRequest) error
|
||||
func (loc *LocalDNSProviderSolver) CleanUp(ch *v1alpha1.ChallengeRequest) error {
|
||||
//domainName := extractDomainName(ch.ResolvedZone)
|
||||
//localip := GetOutboundIP(Dnsserver_net)
|
||||
updateWorkdir()
|
||||
success, err := Execute(
|
||||
Shell,
|
||||
// "-c",
|
||||
AcmeAuthCmd,
|
||||
"unset",
|
||||
ch.DNSName,
|
||||
ch.ResolvedFQDN,
|
||||
ch.Key,
|
||||
"-l",
|
||||
"\"\"", //localip,
|
||||
//"-v",
|
||||
)
|
||||
success, err := sh.UnsetChallenge(ch)
|
||||
klog.Infof("Execute unset TXT returned success: %t\n", success)
|
||||
return err
|
||||
}
|
||||
@ -113,7 +91,7 @@ func (loc *LocalDNSProviderSolver) Initialize(kubeClientConfig *rest.Config, sto
|
||||
return fmt.Errorf("failed to get kubernetes client: %w", err)
|
||||
}
|
||||
loc.client = cl
|
||||
setupWorkdir()
|
||||
sh.SetupWorkdir()
|
||||
klog.Infof("webhook \"%s\" started.", ProviderName)
|
||||
return nil
|
||||
}
|
||||
|
||||
109
pkg/dns/utils.go
109
pkg/dns/utils.go
@ -6,18 +6,8 @@ package dns
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
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
|
||||
@ -35,105 +25,6 @@ func LoadConfig(cfgJSON *extapi.JSON) (LocalDNSProviderConfig, error) {
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func setupWorkdir() {
|
||||
err := createWorkdir()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
updateWorkdir()
|
||||
}
|
||||
|
||||
func updateWorkdir() {
|
||||
wg.Add(4) // Add a count, 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 createWorkdir() error {
|
||||
defer mutex.Unlock()
|
||||
mutex.Lock()
|
||||
finfo, err := os.Stat(Workdir)
|
||||
if os.IsNotExist(err) {
|
||||
klog.Infof("Creating folder \"%s\".", Workdir)
|
||||
err = os.Mkdir(Workdir, 0755)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else if !finfo.IsDir() {
|
||||
return fmt.Errorf("\"%s\" exists, but it's not a folder", Workdir)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
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 {
|
||||
err = CopyFile(sourceFile, destFile, mode)
|
||||
if err == nil {
|
||||
klog.Infof("Updated \"%s\" from \"%s\" folder.", destFile, AcmeDir)
|
||||
}
|
||||
}
|
||||
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 file2 does not exist, return as if file1.modtime > file2.modtime
|
||||
if os.IsNotExist(err) {
|
||||
return 1, nil
|
||||
}
|
||||
// for any other error, return fatal err
|
||||
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 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 err
|
||||
}
|
||||
|
||||
/*
|
||||
// quote quotes the provide value
|
||||
func quote(value string) string {
|
||||
|
||||
228
pkg/shell/shell.go
Normal file
228
pkg/shell/shell.go
Normal file
@ -0,0 +1,228 @@
|
||||
package shell
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/jetstack/cert-manager/pkg/acme/webhook/apis/acme/v1alpha1"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
bashShell = "/bin/bash"
|
||||
zshShell = "/bin/zsh"
|
||||
Workdir = "/workdir"
|
||||
AcmeDir = "/acme"
|
||||
Shell = bashShell
|
||||
|
||||
AuthScript = "acmeauth.sh"
|
||||
DnsUpdScript = "updatedns.sh"
|
||||
KrbConf = "krb5.conf"
|
||||
Keytab = "krb5.keytab"
|
||||
AuthScriptMode = 0744
|
||||
DnsUpdScriptMode = 0744
|
||||
KrbConfMode = 0644
|
||||
KeytabMode = 0644
|
||||
)
|
||||
|
||||
var (
|
||||
AcmeAuthCmd = AcmeDir + "/" + AuthScript
|
||||
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.
|
||||
)
|
||||
|
||||
// CapturingPassThroughWriter is a writer that remembers
|
||||
// data written to it and passes it to w
|
||||
type CapturingPassThroughWriter struct {
|
||||
buf bytes.Buffer
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
// NewCapturingPassThroughWriter creates new CapturingPassThroughWriter
|
||||
func NewCapturingPassThroughWriter(w io.Writer) *CapturingPassThroughWriter {
|
||||
return &CapturingPassThroughWriter{
|
||||
w: w,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *CapturingPassThroughWriter) Write(d []byte) (int, error) {
|
||||
w.buf.Write(d)
|
||||
return w.w.Write(d)
|
||||
}
|
||||
|
||||
// Bytes returns bytes written to the writer
|
||||
func (w *CapturingPassThroughWriter) Bytes() []byte {
|
||||
return w.buf.Bytes()
|
||||
}
|
||||
|
||||
func SetChallenge(ch *v1alpha1.ChallengeRequest) (bool, error) {
|
||||
SetupWorkdir() // update workdir if any of the copied files were updated on host
|
||||
return Execute(
|
||||
Shell,
|
||||
// "-c",
|
||||
AcmeAuthCmd,
|
||||
"set",
|
||||
ch.DNSName,
|
||||
ch.ResolvedFQDN,
|
||||
ch.Key,
|
||||
"-l",
|
||||
"\"\"", //localip,
|
||||
//"-v",
|
||||
)
|
||||
}
|
||||
|
||||
func UnsetChallenge(ch *v1alpha1.ChallengeRequest) (bool, error) {
|
||||
SetupWorkdir() // update workdir if any of the copied files were updated on host
|
||||
return Execute(
|
||||
Shell,
|
||||
// "-c",
|
||||
AcmeAuthCmd,
|
||||
"unset",
|
||||
ch.DNSName,
|
||||
ch.ResolvedFQDN,
|
||||
ch.Key,
|
||||
"-l",
|
||||
"\"\"", //localip,
|
||||
//"-v",
|
||||
)
|
||||
}
|
||||
|
||||
func Execute(shell string, arg ...string) (bool, error) {
|
||||
var errStdout, errStderr error
|
||||
crlf := []byte("\r\n")
|
||||
lf := []byte("\n")
|
||||
|
||||
cmd := exec.Command(shell, arg...)
|
||||
stdoutIn, _ := cmd.StdoutPipe()
|
||||
stderrIn, _ := cmd.StderrPipe()
|
||||
stdout := NewCapturingPassThroughWriter(os.Stdout)
|
||||
stderr := NewCapturingPassThroughWriter(os.Stderr)
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
klog.Fatalf("cmd.Start() failed with '%s'\n", err)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
|
||||
go func() {
|
||||
_, errStdout = io.Copy(stdout, stdoutIn)
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
_, errStderr = io.Copy(stderr, stderrIn)
|
||||
wg.Wait()
|
||||
|
||||
err = cmd.Wait()
|
||||
if err != nil {
|
||||
klog.Fatalf("cmd.Run() failed with %s\n", err)
|
||||
}
|
||||
if errStdout != nil || errStderr != nil {
|
||||
klog.Fatalf("failed to capture stdout or stderr\n")
|
||||
}
|
||||
//outStr, errStr := string(stdout.Bytes()), string(stderr.Bytes())
|
||||
//fmt.Printf("\nout:\n%s\nerr:\n%s\n", outStr, errStr)
|
||||
errb := bytes.TrimSuffix(stderr.Bytes(), crlf)
|
||||
errb = bytes.TrimSuffix(errb, lf)
|
||||
if errb != nil {
|
||||
klog.Infof("err:\n%s\n", string(errb))
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func SetupWorkdir() {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
err := createWorkdir()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
updateWorkdir()
|
||||
}
|
||||
|
||||
func updateWorkdir() {
|
||||
updateIfStale(AuthScript, AuthScriptMode)
|
||||
updateIfStale(DnsUpdScript, DnsUpdScriptMode)
|
||||
updateIfStale(KrbConf, KrbConfMode)
|
||||
updateIfStale(Keytab, KeytabMode)
|
||||
}
|
||||
|
||||
func createWorkdir() error {
|
||||
finfo, err := os.Stat(Workdir)
|
||||
if os.IsNotExist(err) {
|
||||
klog.Infof("Creating folder \"%s\".", Workdir)
|
||||
err = os.Mkdir(Workdir, 0755)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else if !finfo.IsDir() {
|
||||
return fmt.Errorf("\"%s\" exists, but it's not a folder", Workdir)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateIfStale(filename string, mode os.FileMode) error {
|
||||
sourceFile := AcmeDir + "/" + filename
|
||||
destFile := Workdir + "/" + filename
|
||||
result, err := cmpModTime(sourceFile, destFile)
|
||||
if result > 0 {
|
||||
err = CopyFile(sourceFile, destFile, mode)
|
||||
if err == nil {
|
||||
klog.Infof("Updated \"%s\" from \"%s\" folder.", destFile, AcmeDir)
|
||||
}
|
||||
}
|
||||
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 file2 does not exist, return as if file1.modtime > file2.modtime
|
||||
if os.IsNotExist(err) {
|
||||
return 1, nil
|
||||
}
|
||||
// for any other error, return fatal err
|
||||
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 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 err
|
||||
}
|
||||
@ -1,3 +1,3 @@
|
||||
0.0.5-alpha.109
|
||||
20240419-1520
|
||||
109
|
||||
0.0.5-alpha.110
|
||||
20240419-2130
|
||||
110
|
||||
Loading…
Reference in New Issue
Block a user