Skip to content

Commit

Permalink
Add tls for solr (#135)
Browse files Browse the repository at this point in the history
Signed-off-by: pritamdas99 <pritam@appscode.com>
  • Loading branch information
pritamdas99 authored Sep 26, 2024
1 parent 2182ff5 commit 5f1c548
Show file tree
Hide file tree
Showing 21 changed files with 1,506 additions and 5 deletions.
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ require (
k8s.io/klog/v2 v2.130.1
kmodules.xyz/client-go v0.30.13
kmodules.xyz/custom-resources v0.30.0
kubedb.dev/apimachinery v0.47.1-0.20240925065855-706baeb42442
kubedb.dev/apimachinery v0.47.1-0.20240926114257-108f2b41a885
sigs.k8s.io/controller-runtime v0.18.4
xorm.io/xorm v1.3.6
)
Expand All @@ -46,6 +46,7 @@ require (
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cert-manager/cert-manager v1.15.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/eapache/go-resiliency v1.4.0 // indirect
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86c
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
Expand Down Expand Up @@ -802,8 +804,8 @@ kmodules.xyz/monitoring-agent-api v0.29.0 h1:gpFl6OZrlMLb/ySMHdREI9EwGtnJ91oZBn9
kmodules.xyz/monitoring-agent-api v0.29.0/go.mod h1:iNbvaMTgVFOI5q2LJtGK91j4Dmjv4ZRiRdasGmWLKQI=
kmodules.xyz/offshoot-api v0.30.0 h1:dq9F93pu4Q8rL9oTcCk+vGGy8vpS7RNt0GSwx7Bvhec=
kmodules.xyz/offshoot-api v0.30.0/go.mod h1:o9VoA3ImZMDBp3lpLb8+kc2d/KBxioRwCpaKDfLIyDw=
kubedb.dev/apimachinery v0.47.1-0.20240925065855-706baeb42442 h1:MgXbQzSri2ibP/MJFNn9lajy+CzeW5ajsSuMS5bf6mI=
kubedb.dev/apimachinery v0.47.1-0.20240925065855-706baeb42442/go.mod h1:iD6XKg9Blvfd9iYEO0N9GKiSz6r+yzEPZnfkYdESNG4=
kubedb.dev/apimachinery v0.47.1-0.20240926114257-108f2b41a885 h1:Tgo6RxT0xOwbGox9u92GFUj4/1cQYQ+E2SMPm+TWiKQ=
kubedb.dev/apimachinery v0.47.1-0.20240926114257-108f2b41a885/go.mod h1:oyCAmVdJXFLs2jfSqjMFV5pcKdt0v4U4hIuVAaLYv+Q=
kubeops.dev/petset v0.0.5-0.20240603165102-e2d9decb8abe h1:uWyps3VIDFwGuL0yQa0eMGaLg4ofVwpy59U14Trxnz8=
kubeops.dev/petset v0.0.5-0.20240603165102-e2d9decb8abe/go.mod h1:A15vh0r979NsvL65DTIZKWsa/NoX9VapHBAEw1ZsdYI=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
Expand Down
11 changes: 11 additions & 0 deletions solr/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,19 @@ const (
ActionRestore = "RESTORE"
ActionCreate = "CREATE"
ActionDeleteBackup = "DELETEBACKUP"
AddRole = "ADDROLE"
RemoveRole = "REMOVEROLE"
Name = "name"
Role = "role"
Node = "node"
Location = "location"
Repository = "repository"
Collection = "collection"
Async = "async"
Replica = "replica"
MoveReplica = "MOVEREPLICA"
PurgeUnused = "purgeUnused"
TargetNode = "targetNode"
BackupId = "backupId"
DeleteStatus = "DELETESTATUS"
RequestStatus = "REQUESTSTATUS"
Expand All @@ -60,4 +67,8 @@ type SLClient interface {
GetClient() *resty.Client
GetLog() logr.Logger
DecodeBackupResponse(data map[string]interface{}, collection string) ([]byte, error)
MoveReplica(target string, replica string, collection string, async string) (*Response, error)
BalanceReplica(async string) (*Response, error)
AddRole(role, node string) (*Response, error)
RemoveRole(role, node string) (*Response, error)
}
26 changes: 26 additions & 0 deletions solr/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,29 @@ type CreateParams struct {
NumShards int `json:"numShards,omitempty" yaml:"numShards,omitempty"`
ReplicationFactor int `json:"replicationFactor,omitempty" yaml:"replicationFactor,omitempty"`
}

type MoveReplicaInfo struct {
Replica string `json:"replica,omitempty" yaml:"replica,omitempty"`
TargetNode string `json:"targetNode,omitempty" yaml:"targetNode,omitempty"`
Async string `json:"async,omitempty" yaml:"async,omitempty"`
}

type MoveReplicaParams struct {
MoveReplica MoveReplicaInfo `json:"move-replica,omitempty" yaml:"move-replica,omitempty"`
}

type BalanceReplica struct {
WaitForFinalState bool `json:"waitForFinalState,omitempty" yaml:"waitForFinalState,omitempty"`
Async string `json:"async,omitempty" yaml:"async,omitempty"`
}

type CoreList struct {
coreName string
collection string
}

type UpdateList struct {
target string
replica string
collection string
}
41 changes: 40 additions & 1 deletion solr/kubedb_client_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@ package solr

import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"net"
"net/http"
"time"

"k8s.io/klog/v2"

"github.com/Masterminds/semver/v3"
gerr "github.com/pkg/errors"
core "k8s.io/api/core/v1"
Expand Down Expand Up @@ -75,7 +79,7 @@ func (o *KubeDBClientBuilder) WithContext(ctx context.Context) *KubeDBClientBuil

func (o *KubeDBClientBuilder) GetSolrClient() (*Client, error) {
if o.podName != "" {
o.url = o.GetHostPath(o.db)
o.url = fmt.Sprintf("%v://%s.%s.%s.svc.cluster.local:%d", o.db.GetConnectionScheme(), o.podName, o.db.GoverningServiceName(), o.db.GetNamespace(), kubedb.SolrRestPort)
}
if o.url == "" {
o.url = o.GetHostPath(o.db)
Expand All @@ -99,6 +103,41 @@ func (o *KubeDBClientBuilder) GetSolrClient() (*Client, error) {
log: o.log,
}

// If EnableSSL is true set tls config,
// provide client certs and root CA
if o.db.Spec.EnableSSL {
var certSecret core.Secret
err := o.kc.Get(o.ctx, types.NamespacedName{
Namespace: o.db.Namespace,
Name: o.db.GetCertSecretName(api.SolrClientCert),
}, &certSecret)
if err != nil {
klog.Error(err, "failed to get serverCert secret")
return nil, err
}

// get tls cert, clientCA and rootCA for tls config
// use server cert ca for rootca as issuer ref is not taken into account
clientCA := x509.NewCertPool()
rootCA := x509.NewCertPool()

crt, err := tls.X509KeyPair(certSecret.Data[core.TLSCertKey], certSecret.Data[core.TLSPrivateKeyKey])
if err != nil {
klog.Error(err, "failed to create certificate for TLS config")
return nil, err
}
clientCA.AppendCertsFromPEM(certSecret.Data[kubedb.CACert])
rootCA.AppendCertsFromPEM(certSecret.Data[kubedb.CACert])

config.transport.TLSClientConfig = &tls.Config{
Certificates: []tls.Certificate{crt},
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: clientCA,
RootCAs: rootCA,
MaxVersion: tls.VersionTLS13,
}
}

var authSecret core.Secret
if !o.db.Spec.DisableSecurity {
err := o.kc.Get(o.ctx, types.NamespacedName{
Expand Down
88 changes: 88 additions & 0 deletions solr/solrv8.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,3 +342,91 @@ func (sc *SLClientV8) DecodeBackupResponse(data map[string]interface{}, collecti
return b, nil

}

func (sc *SLClientV8) MoveReplica(target string, replica string, collection string, async string) (*Response, error) {
sc.Config.log.V(5).Info(fmt.Sprintf("Move replica %v of collection %v to target node %v", replica, collection, target))
req := sc.Client.R().SetDoNotParseResponse(true)
params := map[string]string{
Action: MoveReplica,
Collection: collection,
Replica: replica,
TargetNode: target,
Async: async,
}
req.SetQueryParams(params)
//req.SetHeader("Content-Type", "application/json")
//moveReplica := &MoveReplicaParams{
// MoveReplica: MoveReplicaInfo{
// TargetNode: target,
// Replica: replica,
// Async: async,
// },
//}
//req.SetBody(moveReplica)
res, err := req.Post("/solr/admin/collections")
if err != nil {
sc.Config.log.Error(err, "Failed to send http request to move replica")
return nil, err
}

moveReplicaResponse := &Response{
Code: res.StatusCode(),
header: res.Header(),
body: res.RawBody(),
}
return moveReplicaResponse, nil
}

func (sc *SLClientV8) BalanceReplica(async string) (*Response, error) {
return nil, nil
}

func (sc *SLClientV8) AddRole(role, node string) (*Response, error) {
sc.Config.log.V(5).Info(fmt.Sprintf("Add role %s in node %s", role, node))
req := sc.Client.R().SetDoNotParseResponse(true)
req.SetHeader("Content-Type", "application/json")
params := map[string]string{
Action: AddRole,
Node: node,
Role: role,
}
req.SetQueryParams(params)

res, err := req.Get("/solr/admin/collections")
if err != nil {
sc.Config.log.Error(err, "Failed to send http request to add a role")
return nil, err
}

backupResponse := &Response{
Code: res.StatusCode(),
header: res.Header(),
body: res.RawBody(),
}
return backupResponse, nil
}

func (sc *SLClientV8) RemoveRole(role, node string) (*Response, error) {
sc.Config.log.V(5).Info(fmt.Sprintf("Remove role %s in node %s", role, node))
req := sc.Client.R().SetDoNotParseResponse(true)
req.SetHeader("Content-Type", "application/json")
params := map[string]string{
Action: RemoveRole,
Node: node,
Role: role,
}
req.SetQueryParams(params)

res, err := req.Get("/solr/admin/collections")
if err != nil {
sc.Config.log.Error(err, "Failed to send http request to remove a role")
return nil, err
}

backupResponse := &Response{
Code: res.StatusCode(),
header: res.Header(),
body: res.RawBody(),
}
return backupResponse, nil
}
99 changes: 99 additions & 0 deletions solr/solrv9.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,3 +330,102 @@ func (sc *SLClientV9) DecodeBackupResponse(data map[string]interface{}, collecti
klog.Info(fmt.Sprintf("Response for collection %s\n%v", collection, string(b)))
return b, nil
}

func (sc *SLClientV9) MoveReplica(target string, replica string, collection string, async string) (*Response, error) {
sc.Config.log.V(5).Info(fmt.Sprintf("Move replica %v of collection %v to target node %v", replica, collection, target))
req := sc.Client.R().SetDoNotParseResponse(true)
req.SetHeader("Content-Type", "application/json")
moveReplica := &MoveReplicaParams{
MoveReplica: MoveReplicaInfo{
TargetNode: target,
Replica: replica,
Async: async,
},
}
req.SetBody(moveReplica)
res, err := req.Post(fmt.Sprintf("/api/collections/%s", collection))
if err != nil {
sc.Config.log.Error(err, "Failed to send http request to move replica")
return nil, err
}

moveReplicaResponse := &Response{
Code: res.StatusCode(),
header: res.Header(),
body: res.RawBody(),
}
return moveReplicaResponse, nil
}

func (sc *SLClientV9) BalanceReplica(async string) (*Response, error) {
sc.Config.log.V(5).Info("Balance replica")
req := sc.Client.R().SetDoNotParseResponse(true)
req.SetHeader("Content-Type", "application/json")
balanceReplica := &BalanceReplica{
WaitForFinalState: true,
Async: async,
}
req.SetBody(balanceReplica)
res, err := req.Post("/api/cluster/replicas/balance")
if err != nil {
sc.Config.log.Error(err, "Failed to send http request to move replica")
return nil, err
}

moveReplicaResponse := &Response{
Code: res.StatusCode(),
header: res.Header(),
body: res.RawBody(),
}
return moveReplicaResponse, nil
}

func (sc *SLClientV9) AddRole(role, node string) (*Response, error) {
sc.Config.log.V(5).Info(fmt.Sprintf("Add role %s in node %s", role, node))
req := sc.Client.R().SetDoNotParseResponse(true)
req.SetHeader("Content-Type", "application/json")
params := map[string]string{
Action: AddRole,
Node: node,
Role: role,
}
req.SetQueryParams(params)

res, err := req.Get("/solr/admin/collections")
if err != nil {
sc.Config.log.Error(err, "Failed to send http request to add a role")
return nil, err
}

backupResponse := &Response{
Code: res.StatusCode(),
header: res.Header(),
body: res.RawBody(),
}
return backupResponse, nil
}

func (sc *SLClientV9) RemoveRole(role, node string) (*Response, error) {
sc.Config.log.V(5).Info(fmt.Sprintf("Remove role %s in node %s", role, node))
req := sc.Client.R().SetDoNotParseResponse(true)
req.SetHeader("Content-Type", "application/json")
params := map[string]string{
Action: RemoveRole,
Node: node,
Role: role,
}
req.SetQueryParams(params)

res, err := req.Get("/solr/admin/collections")
if err != nil {
sc.Config.log.Error(err, "Failed to send http request to remove a role")
return nil, err
}

backupResponse := &Response{
Code: res.StatusCode(),
header: res.Header(),
body: res.RawBody(),
}
return backupResponse, nil
}
Loading

0 comments on commit 5f1c548

Please sign in to comment.