Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ code-review: $(BUILD_TARGETS)/generate golangci copyright ## Full code review a
# ----------------------------------------------------------------------------------------------------------------------
.PHONY: golangci
golangci: $(TOOLS_BIN)/golangci-lint ## Go code review
$(TOOLS_BIN)/golangci-lint run -v --timeout=5m --skip-dirs=.*/fakes --skip-files=zz_.*,generated/*,pkg/data/assets... ./api/... ./controllers/... ./pkg/... ./runner/...
$(TOOLS_BIN)/golangci-lint run -v --timeout=5m --exclude='G402:' --skip-dirs=.*/fakes --skip-files=zz_.*,generated/*,pkg/data/assets... ./api/... ./controllers/... ./pkg/... ./runner/...
$(TOOLS_BIN)/golangci-lint run -v --timeout=5m --exclude='G107:' --exclude='should not use dot imports' ./test/... ./pkg/fakes/...


Expand Down
19 changes: 17 additions & 2 deletions api/v1/hasher.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ package v1
import (
"encoding/binary"
"fmt"
"github.com/davecgh/go-spew/spew"
"hash"
"hash/fnv"
"k8s.io/apimachinery/pkg/util/rand"
hashutil "k8s.io/kubernetes/pkg/util/hash"
)

func EnsureHashLabel(c *Coherence) (string, bool) {
Expand All @@ -33,7 +34,7 @@ func EnsureHashLabel(c *Coherence) (string, bool) {
// The hash will be safe encoded to avoid bad words.
func ComputeHash(template *CoherenceResourceSpec, collisionCount *int32) string {
podTemplateSpecHasher := fnv.New32a()
hashutil.DeepHashObject(podTemplateSpecHasher, *template)
DeepHashObject(podTemplateSpecHasher, *template)

// Add collisionCount in the hash if it exists.
if collisionCount != nil {
Expand All @@ -44,3 +45,17 @@ func ComputeHash(template *CoherenceResourceSpec, collisionCount *int32) string

return rand.SafeEncodeString(fmt.Sprint(podTemplateSpecHasher.Sum32()))
}

// DeepHashObject writes specified object to hash using the spew library
// which follows pointers and prints actual values of the nested objects
// ensuring the hash does not change when a pointer changes.
func DeepHashObject(hasher hash.Hash, objectToWrite interface{}) {
hasher.Reset()
printer := spew.ConfigState{
Indent: " ",
SortKeys: true,
DisableMethods: true,
SpewKeys: true,
}
_, _ = printer.Fprintf(hasher, "%#v", objectToWrite)
}
92 changes: 92 additions & 0 deletions controllers/statefulset/http.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/

package statefulset

import (
"crypto/tls"
"fmt"
"github.com/oracle/coherence-operator/pkg/operator"
"io/ioutil"
"k8s.io/apimachinery/pkg/util/net"
"net/http"
"net/url"
"time"
)

// NewHTTPProbe creates Probe that will skip TLS verification while probing.
func NewHTTPProbe() HTTPProbe {
tlsConfig := &tls.Config{InsecureSkipVerify: true}
return NewHTTPProbeWithTLSConfig(tlsConfig)
}

// NewHTTPProbeWithTLSConfig takes tls config as parameter.
func NewHTTPProbeWithTLSConfig(config *tls.Config) HTTPProbe {
transport := net.SetTransportDefaults(&http.Transport{TLSClientConfig: config, DisableKeepAlives: true})
return httpProbe{transport}
}

// HTTPProbe is an interface that defines the Probe function for doing HTTP readiness/liveness checks.
type HTTPProbe interface {
Probe(url *url.URL, headers http.Header, timeout time.Duration) (Result, string, error)
}

type httpProbe struct {
transport *http.Transport
}

// Probe returns a ProbeRunner capable of running an HTTP check.
func (pr httpProbe) Probe(url *url.URL, headers http.Header, timeout time.Duration) (Result, string, error) {
return DoHTTPProbe(url, headers, &http.Client{Timeout: timeout, Transport: pr.transport})
}

// GetHTTPInterface is an interface for making HTTP requests, that returns a response and error.
type GetHTTPInterface interface {
Do(req *http.Request) (*http.Response, error)
}

// DoHTTPProbe checks if a GET request to the url succeeds.
// If the HTTP response code is successful (i.e. 400 > code >= 200), it returns Success.
// If the HTTP response code is unsuccessful or HTTP communication fails, it returns Failure.
// This is exported because some other packages may want to do direct HTTP probes.
func DoHTTPProbe(url *url.URL, headers http.Header, client GetHTTPInterface) (Result, string, error) {
req, err := http.NewRequest("GET", url.String(), nil)
if err != nil {
// Convert errors into failures to catch timeouts.
return Failure, err.Error(), nil
}
if _, ok := headers["User-Agent"]; !ok {
if headers == nil {
headers = http.Header{}
}
// explicitly set User-Agent, so it's not set to default Go value
headers.Set("User-Agent", fmt.Sprintf("coherence-operator/%s", operator.GetVersion()))
}
req.Header = headers
if headers.Get("Host") != "" {
req.Host = headers.Get("Host")
}
res, err := client.Do(req)
if err != nil {
// Convert errors into failures to catch timeouts.
return Failure, err.Error(), nil
}
defer closeBody(res)
b, err := ioutil.ReadAll(res.Body)
if err != nil {
return Failure, "", err
}
body := string(b)
if res.StatusCode >= http.StatusOK && res.StatusCode < http.StatusBadRequest {
return Success, body, nil
}
return Failure, fmt.Sprintf("HTTP probe failed with statuscode: %d", res.StatusCode), nil
}

func closeBody(res *http.Response) {
// close the response body, ignoring any errors
_ = res.Body.Close()
}
23 changes: 16 additions & 7 deletions controllers/statefulset/probe.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,25 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/rest"
"k8s.io/kubernetes/pkg/probe"
httpprobe "k8s.io/kubernetes/pkg/probe/http"
tcprobe "k8s.io/kubernetes/pkg/probe/tcp"
"net/http"
"net/url"
"sigs.k8s.io/controller-runtime/pkg/client"
"strconv"
"strings"
)

// Result is a string used to handle the results for probing container readiness/livenss
type Result string

const (
// Success Result
Success Result = "success"
// Failure Result
Failure Result = "failure"
// Unknown Result
Unknown Result = "unknown"
)

type CoherenceProbe struct {
Client client.Client
Config *rest.Config
Expand Down Expand Up @@ -270,12 +279,12 @@ func (in *CoherenceProbe) ProbeUsingHTTP(pod corev1.Pod, handler *coh.Probe) (bo
}
}

p := httpprobe.New()
p := NewHTTPProbe()
result, s, err := p.Probe(u, header, handler.GetTimeout())

log.Info(fmt.Sprintf("HTTP Probe URL: %s result=%v msg=%s error=%v", u.String(), result, s, err))

return result == probe.Success, err
return result == Success, err
}

func (in *CoherenceProbe) ProbeUsingTCP(pod corev1.Pod, handler *coh.Probe) (bool, error) {
Expand All @@ -297,12 +306,12 @@ func (in *CoherenceProbe) ProbeUsingTCP(pod corev1.Pod, handler *coh.Probe) (boo
return false, err
}

p := tcprobe.New()
p := NewTCPProbe()
result, _, err := p.Probe(host, port, handler.GetTimeout())

log.Info(fmt.Sprintf("TCP Probe: %s:%d result=%s error=%s", host, port, result, err))

return result == probe.Success, err
return result == Success, err
}

func (in *CoherenceProbe) findPort(pod corev1.Pod, port intstr.IntOrString) (int, error) {
Expand Down
47 changes: 47 additions & 0 deletions controllers/statefulset/tcp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/

package statefulset

import (
"net"
"strconv"
"time"
)

// NewTCPProbe creates TCPProbe.
func NewTCPProbe() TCPProbe {
return tcpProbe{}
}

// TCPProbe is an interface that defines the Probe function for doing TCP readiness/liveness checks.
type TCPProbe interface {
Probe(host string, port int, timeout time.Duration) (Result, string, error)
}

type tcpProbe struct{}

// Probe returns a ProbeRunner capable of running an TCP check.
func (pr tcpProbe) Probe(host string, port int, timeout time.Duration) (Result, string, error) {
return DoTCPProbe(net.JoinHostPort(host, strconv.Itoa(port)), timeout)
}

// DoTCPProbe checks that a TCP socket to the address can be opened.
// If the socket can be opened, it returns Success
// If the socket fails to open, it returns Failure.
// This is exported because some other packages may want to do direct TCP probes.
func DoTCPProbe(addr string, timeout time.Duration) (Result, string, error) {
conn, err := net.DialTimeout("tcp", addr, timeout)
if err != nil {
// Convert errors to failures to handle timeouts.
return Failure, err.Error(), nil
}
err = conn.Close()
if err != nil {
log.Error(err, "Unexpected error closing TCP probe socket")
}
return Success, "", nil
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.16

require (
github.com/coreos/prometheus-operator v0.38.1-0.20200424145508-7e176fda06cc
github.com/davecgh/go-spew v1.1.1
github.com/elastic/go-elasticsearch/v7 v7.6.0
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32
github.com/go-logr/logr v0.4.0
Expand All @@ -19,7 +20,6 @@ require (
k8s.io/apiextensions-apiserver v0.22.2
k8s.io/apimachinery v0.22.2
k8s.io/client-go v12.0.0+incompatible
k8s.io/kubernetes v1.13.0
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a
sigs.k8s.io/controller-runtime v0.10.0
sigs.k8s.io/testing_frameworks v0.1.2
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1243,8 +1243,6 @@ k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C
k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM=
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
k8s.io/kubernetes v1.13.0 h1:qTfB+u5M92k2fCCCVP2iuhgwwSOv1EkAkvQY1tQODD8=
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/utils v0.0.0-20191114200735-6ca3b61696b6/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
Expand Down
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ func execute() {
func initialiseOperator(ctx context.Context, v *version.Version, cl client.Client) {
opLog := ctrl.Log.WithName("operator")

operator.SetVersion(Version)

// Ensure that the CRDs exist
if operator.ShouldInstallCRDs() {
err := coh.EnsureCRDs(ctx, v, scheme, cl)
Expand Down
9 changes: 9 additions & 0 deletions pkg/operator/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ const (
var setupLog = ctrl.Log.WithName("setup")

var (
operatorVersion = "unknown"
DefaultSiteLabels = []string{corev1.LabelTopologyZone, corev1.LabelFailureDomainBetaZone}
DefaultRackLabels = []string{corev1.LabelTopologyRegion, corev1.LabelFailureDomainBetaRegion,
corev1.LabelTopologyZone, corev1.LabelFailureDomainBetaZone}
Expand Down Expand Up @@ -315,3 +316,11 @@ func DetectKubernetesVersion(cs clients.ClientSet) (*version.Version, error) {
}
return version.ParseSemantic(sv.GitVersion)
}

func GetVersion() string {
return operatorVersion
}

func SetVersion(v string) {
operatorVersion = v
}