Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tls for solr #135

Merged
merged 5 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.20240925131439-ffff84384534
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.20240925131439-ffff84384534 h1:W2gbr6/rW6eI3wcO9hufLzthrzIGUrJEnmS+O8Y6fuk=
kubedb.dev/apimachinery v0.47.1-0.20240925131439-ffff84384534/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["ca.crt"])
rootCA.AppendCertsFromPEM(certSecret.Data["ca.crt"])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add constant


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
Loading