mirror of
https://github.com/xcat2/confluent.git
synced 2025-09-23 10:38:14 +00:00
Add a general utility for confluent in golang
This commit is contained in:
133
confluent_osdeploy/utils/confusebox/apiclient.go
Normal file
133
confluent_osdeploy/utils/confusebox/apiclient.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"net/http"
|
||||
"crypto/x509"
|
||||
"crypto/tls"
|
||||
"strings"
|
||||
"errors"
|
||||
)
|
||||
type ApiClient struct {
|
||||
server string
|
||||
urlserver string
|
||||
apikey string
|
||||
nodename string
|
||||
webclient *http.Client
|
||||
}
|
||||
|
||||
func NewApiClient(cafile string, keyfile string, nodename string, server string) (*ApiClient, error) {
|
||||
currcacerts, err := os.ReadFile(cafile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cacerts := x509.NewCertPool()
|
||||
cacerts.AppendCertsFromPEM(currcacerts)
|
||||
apikey := []byte("")
|
||||
if keyfile != "" {
|
||||
apikey, err = os.ReadFile(keyfile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if apikey[len(apikey) - 1] == 0xa {
|
||||
apikey = apikey[:len(apikey)-1]
|
||||
}
|
||||
}
|
||||
if nodename == "" {
|
||||
cinfo, err := os.ReadFile("/etc/confluent/confliuent.info")
|
||||
if err != nil {
|
||||
nodename, err = os.Hostname()
|
||||
if err != nil { return nil, err }
|
||||
}
|
||||
cinfolines := bytes.Split(cinfo, []byte("\n"))
|
||||
if bytes.Contains(cinfolines[0], []byte("NODENAME")) {
|
||||
cnodebytes := bytes.Split(cinfolines[0], []byte(" "))
|
||||
nodename = string(cnodebytes[0])
|
||||
}
|
||||
}
|
||||
urlserver := server
|
||||
if strings.Contains(server, ":") {
|
||||
if strings.Contains(server, "%") && !strings.Contains(server, "%25") {
|
||||
server = strings.Replace(server, "%", "%25", 1)
|
||||
}
|
||||
urlserver = fmt.Sprintf("[%s]", server)
|
||||
if strings.Contains(server, "%") {
|
||||
server = server[:strings.Index(server, "%")]
|
||||
}
|
||||
}
|
||||
webclient := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
RootCAs: cacerts,
|
||||
ServerName: server,
|
||||
},
|
||||
},
|
||||
}
|
||||
vc := ApiClient{server, urlserver, string(apikey), nodename, webclient}
|
||||
return &vc, nil
|
||||
}
|
||||
|
||||
func (apiclient *ApiClient) RegisterKey(crypted string, hmac string) (error) {
|
||||
cryptbytes := []byte(crypted)
|
||||
_, err := apiclient.request("/confluent-api/self/registerapikey", "", &cryptbytes, "", hmac)
|
||||
return err
|
||||
}
|
||||
|
||||
func (apiclient *ApiClient) Fetch(url string, outputfile string, mime string) (error) {
|
||||
outp, err := os.Create(outputfile)
|
||||
if err != nil { return err }
|
||||
defer outp.Close()
|
||||
rsp, err := apiclient.request(url, mime, nil, "", "")
|
||||
if err != nil { return err }
|
||||
_, err = io.Copy(outp, rsp)
|
||||
return err
|
||||
}
|
||||
|
||||
func (apiclient *ApiClient) GrabText(url string, mime string) (string, error){
|
||||
rsp, err := apiclient.request(url, mime, nil, "", "")
|
||||
if err != nil { return "", err }
|
||||
rspdata, err := io.ReadAll(rsp)
|
||||
if err != nil { return "", err }
|
||||
rsptxt := string(rspdata)
|
||||
return rsptxt, nil
|
||||
}
|
||||
|
||||
func (apiclient *ApiClient) request(url string, mime string, body *[]byte, method string, hmac string) (io.ReadCloser, error) {
|
||||
if ! strings.Contains(url, "https://") {
|
||||
url = fmt.Sprintf("https://%s%s", apiclient.urlserver, url)
|
||||
}
|
||||
if method == "" {
|
||||
if body != nil {
|
||||
method = http.MethodPost
|
||||
} else {
|
||||
method = http.MethodGet
|
||||
}
|
||||
}
|
||||
var err error
|
||||
var rq *http.Request
|
||||
if body == nil {
|
||||
rq, err = http.NewRequest(method, url, nil)
|
||||
} else {
|
||||
rq, err = http.NewRequest(method, url, bytes.NewBuffer(*body))
|
||||
}
|
||||
if err != nil { return nil, err }
|
||||
if (mime != "") { rq.Header.Set("Accept", mime) }
|
||||
rq.Header.Set("CONFLUENT_NODENAME", apiclient.nodename)
|
||||
if len(hmac) > 0 {
|
||||
rq.Header.Set("CONFLUENT_CRYPTHMAC", hmac)
|
||||
} else {
|
||||
|
||||
rq.Header.Set("CONFLUENT_APIKEY", apiclient.apikey)
|
||||
}
|
||||
rsp, err := apiclient.webclient.Do(rq)
|
||||
if err != nil { return nil, err }
|
||||
if rsp.StatusCode >= 300 {
|
||||
err = errors.New(rsp.Status)
|
||||
return nil, err
|
||||
}
|
||||
return rsp.Body, err
|
||||
}
|
||||
|
44
confluent_osdeploy/utils/confusebox/genpasshmac.go
Normal file
44
confluent_osdeploy/utils/confusebox/genpasshmac.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/go-crypt/crypt/algorithm/shacrypt"
|
||||
"os"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
)
|
||||
|
||||
func genpasshmac(hmackeyfile string) (string, string, string, error) {
|
||||
randbytes := make([]byte, 36)
|
||||
_, err := rand.Read(randbytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
password := base64.StdEncoding.EncodeToString(randbytes)
|
||||
hasher, err := shacrypt.New(shacrypt.WithVariant(shacrypt.VariantSHA256), shacrypt.WithIterations(5000))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
digest, err := hasher.Hash(password)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cryptpass := digest.Encode()
|
||||
hmackey, err := os.ReadFile(hmackeyfile)
|
||||
if err != nil { return "", "", "", err }
|
||||
keylines := bytes.Split(hmackey, []byte("\n"))
|
||||
if bytes.Contains(keylines[0], []byte("apitoken:")) {
|
||||
keyparts := bytes.Split(keylines[0], []byte(" "))
|
||||
hmackey = keyparts[1]
|
||||
}
|
||||
|
||||
hmacer := hmac.New(sha256.New, hmackey)
|
||||
hmacer.Write([]byte(cryptpass))
|
||||
hmacresult := hmacer.Sum(nil)
|
||||
hmacout := base64.StdEncoding.EncodeToString(hmacresult)
|
||||
return password, cryptpass, hmacout, nil
|
||||
}
|
||||
|
7
confluent_osdeploy/utils/confusebox/go.mod
Normal file
7
confluent_osdeploy/utils/confusebox/go.mod
Normal file
@@ -0,0 +1,7 @@
|
||||
module confusebox
|
||||
|
||||
go 1.23.6
|
||||
|
||||
require github.com/go-crypt/crypt v0.3.3
|
||||
|
||||
require github.com/go-crypt/x v0.3.4 // indirect
|
4
confluent_osdeploy/utils/confusebox/go.sum
Normal file
4
confluent_osdeploy/utils/confusebox/go.sum
Normal file
@@ -0,0 +1,4 @@
|
||||
github.com/go-crypt/crypt v0.3.3 h1:mBSh8U+vwDm3V+UHNMQqsxV0clzlvKbLcJXcafYFpCs=
|
||||
github.com/go-crypt/crypt v0.3.3/go.mod h1:ex5C1b58/tzCW6/rJfcdf5Y2TjgzmWVtX57sjpN3pUQ=
|
||||
github.com/go-crypt/x v0.3.4 h1:zgpaI55VOAbkkRup9+tLaZ02IWTV/xz63tohoY0t9+Y=
|
||||
github.com/go-crypt/x v0.3.4/go.mod h1:+uHWqfzD3S6YWxm18/Qp+4VcuBb0Le9dGUhX0zaWicU=
|
86
confluent_osdeploy/utils/confusebox/main.go
Normal file
86
confluent_osdeploy/utils/confusebox/main.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"os"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var nodename string
|
||||
var cacerts string
|
||||
var apikey string
|
||||
var usejson bool
|
||||
var confluentsrv string
|
||||
hmacreg := flag.NewFlagSet("hmacregister", flag.ExitOnError)
|
||||
hmacreg.StringVar(&apikey, "k", "/etc/confluent/apikey", "Output file for the api key")
|
||||
hmacKey := hmacreg.String("i", "", "Identity yaml file")
|
||||
hmacreg.StringVar(&cacerts, "c", "/etc/confluent/ca.pem", "Certeficate authorities to use in PEM")
|
||||
hmacreg.StringVar(&nodename, "n", "", "Node name")
|
||||
hmacreg.StringVar(&confluentsrv, "s", "", "Confluent server to request from")
|
||||
|
||||
invokeapi := flag.NewFlagSet("invoke", flag.ExitOnError)
|
||||
invokeapi.StringVar(&nodename, "n", "", "Node name")
|
||||
|
||||
invokeapi.StringVar(&cacerts, "c", "/etc/confluent/ca.pem", "Certeficate authorities to use in PEM")
|
||||
invokeapi.StringVar(&apikey, "k", "/etc/confluent/confluent.apikey", "File containing Confluent API key")
|
||||
invokeapi.BoolVar(&usejson, "j", false, "Request JSON formatted reply")
|
||||
outputfile := invokeapi.String("o", "", "Filename to store download to")
|
||||
invokeapi.StringVar(&confluentsrv, "s", "", "Confluent server to request from")
|
||||
|
||||
if confluentsrv == "" {
|
||||
dcfg, err := os.ReadFile("/etc/confluent/confluent.deploycfg")
|
||||
if err == nil {
|
||||
dcfglines := bytes.Split(dcfg, []byte("\n"))
|
||||
for _, dcfgline := range(dcfglines) {
|
||||
dkeyval := bytes.Split(dcfgline, []byte(" "))
|
||||
if bytes.Contains(dkeyval[0], []byte("deploy_server")) && (bytes.Contains(dkeyval[1], []byte(".")) || bytes.Contains(dkeyval[1], []byte(":"))) {
|
||||
confluentsrv = string(dkeyval[1])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
_, err := os.ReadFile("/etc/confluent/confluent.info")
|
||||
if err != nil {
|
||||
panic("Unable to determine Confluent server")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(os.Args) < 2 {
|
||||
panic("Insufficient arguments, no subcommand")
|
||||
}
|
||||
switch os.Args[1] {
|
||||
case "hmacregister":
|
||||
hmacreg.Parse(os.Args[2:])
|
||||
password, crypted, hmac, err := genpasshmac(*hmacKey)
|
||||
if err != nil { panic(err) }
|
||||
//apiclient(cacerts, "/confluent-api/self/registerapikey", apikey, nodename, usejson)
|
||||
apiclient, err := NewApiClient(cacerts, "", nodename, confluentsrv)
|
||||
if err != nil { panic(err) }
|
||||
err = apiclient.RegisterKey(crypted, hmac)
|
||||
if err != nil { panic(err) }
|
||||
outp, err := os.Create(apikey)
|
||||
if err != nil { panic(err) }
|
||||
defer outp.Close()
|
||||
outp.Write([]byte(password))
|
||||
case "invoke":
|
||||
invokeapi.Parse(os.Args[2:])
|
||||
apiclient, err := NewApiClient(cacerts, apikey, nodename, confluentsrv)
|
||||
if err != nil { panic(err) }
|
||||
mime := ""
|
||||
if usejson {
|
||||
mime = "application/json"
|
||||
}
|
||||
if *outputfile != "" {
|
||||
apiclient.Fetch(invokeapi.Arg(0), *outputfile, mime)
|
||||
}
|
||||
rsp, err := apiclient.GrabText(invokeapi.Arg(0), mime)
|
||||
if err != nil { panic(err) }
|
||||
fmt.Println(rsp)
|
||||
default:
|
||||
panic("Unrecognized subcommand")
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user