Skip to content

Commit

Permalink
Adding a chRoot option, and chRoot validation/creation, for all ZK re…
Browse files Browse the repository at this point in the history
…ferences. (#62)

- Fixed & Expanded docs
- Made resolving of labels & annotation changes better.
  • Loading branch information
HoustonPutman authored Jan 10, 2020
1 parent 0bcff50 commit 01f2411
Show file tree
Hide file tree
Showing 13 changed files with 505 additions and 196 deletions.
86 changes: 52 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
# Solr Operator
[![Build Status](https://travis-ci.com/bloomberg/solr-operator.svg?branch=master)](https://travis-ci.com/bloomberg/solr-operator) [![Go Report Card](https://goreportcard.com/badge/github.com/bloomberg/solr-operator)](https://goreportcard.com/report/github.com/bloomberg/solr-operator) ![Latest Version](https://img.shields.io/github/tag/bloomberg/solr-operator) [![Docker Pulls](https://img.shields.io/docker/pulls/bloomberg/solr-operator)](https://hub.docker.com/r/bloomberg/solr-operator/)
[![Latest Version](https://img.shields.io/github/tag/bloomberg/solr-operator)](https://github.com/bloomberg/solr-operator/releases)
[![Build Status](https://travis-ci.com/bloomberg/solr-operator.svg?branch=master)](https://travis-ci.com/bloomberg/solr-operator)
[![License](https://img.shields.io/badge/LICENSE-Apache2.0-ff69b4.svg)](http://www.apache.org/licenses/LICENSE-2.0.html)
[![Go Report Card](https://goreportcard.com/badge/github.com/bloomberg/solr-operator)](https://goreportcard.com/report/github.com/bloomberg/solr-operator)
[![Commit since last release](https://img.shields.io/github/commits-since/bloomberg/solr-operator/latest.svg)](https://github.com/bloomberg/solr-operator/commits/master)
[![Docker Pulls](https://img.shields.io/docker/pulls/bloomberg/solr-operator)](https://hub.docker.com/r/bloomberg/solr-operator/)
[![Slack](https://img.shields.io/badge/slack-join_chat-white.svg?logo=slack&style=social)](https://kubernetes.slack.com/messages/solr-operator)

The __Solr Operator__ manages Apache Solr Clouds within Kubernetes. It is built on top of the [Kube Builder](https://github.com/kubernetes-sigs/kubebuilder) framework.

The project is currently in beta (`v1beta1`), and while we do not anticipate changing the API in backwards-incompatible ways there is no such guarantee yet.

If you run into issues using the Solr Operator, please:
- Reference the [version compatibility and upgrade notes](#version-compatability--upgrade-notes) provided below
- Create a Github Issue in this repo, describing your problem with as much detail as possible
- Reach out on our Slack channel!

Join us on the [#solr-operator](https://kubernetes.slack.com/messages/solr-operator) channel in the official Kubernetes slack workspace.

## Menu

- [Getting Started](#getting-started)
Expand All @@ -13,6 +26,7 @@ The project is currently in beta (`v1beta1`), and while we do not anticipate cha
- [Solr Backups](#solr-backups)
- [Solr Metrics](#solr-prometheus-exporter)
- [Contributions](#contributions)
- [Version Compatibility and Upgrade Notes](#version-compatability--upgrade-notes)
- [License](#license)
- [Code of Conduct](#code-of-conduct)
- [Security Vulnerability Reporting](#security-vulnerability-reporting)
Expand Down Expand Up @@ -133,6 +147,38 @@ NAME VERSION DESIREDNODES NODES READ
solrcloud.solr.bloomberg.com/example 8.1.1 4 4 4 47h
```

## Zookeeper Reference

Solr Clouds require an Apache Zookeeper to connect to.

The Solr operator gives a few options.

**Note** - Both options below come with options to specify a `chroot`, or a ZNode path for solr to use as it's base "directory" in Zookeeper. Before the operator creates or updates a StatefulSet with a given `chroot`, it will first ensure that the given ZNode path exists and if it doesn't the operator will create all necessary ZNodes in the path. If no chroot is given, a default of `/` will be used, which doesn't require the existence check previously mentioned. If a chroot is provided without a prefix of `/`, the operator will add the prefix, as it is required by Zookeeper.

### ZK Connection Info

This is an external/internal connection string as well as an optional chRoot to an already running Zookeeeper ensemble.
If you provide an external connection string, you do not _have_ to provide an internal one as well.

### Provided Instance

If you do not require the Solr cloud to run cross-kube cluster, and do not want to manage your own Zookeeper ensemble,
the solr-operator can manage Zookeeper ensemble(s) for you.

#### Zookeeper

Using the [zookeeper-operator](https://github.com/pravega/zookeeper-operator), a new Zookeeper ensemble can be spun up for
each solrCloud that has this option specified.

The startup parameter `zookeeper-operator` must be provided on startup of the solr-operator for this parameter to be available.

#### Zetcd

Using [etcd-operator](https://github.com/coreos/etcd-operator), a new Etcd ensemble can be spun up for each solrCloud that has this option specified.
A [Zetcd](https://github.com/etcd-io/zetcd) deployment is also created so that Solr can interact with Etcd as if it were a Zookeeper ensemble.

The startup parameter `etcd-operator` must be provided on startup of the solr-operator for this parameter to be available.

### Solr Collections

Solr-operator can manage the creation, deletion and modification of Solr collections.
Expand Down Expand Up @@ -214,38 +260,6 @@ Aliases can be useful when migrating from one collection to another without havi
Routed aliases are presently not supported


## Zookeeper
=======
### Zookeeper Reference

Solr Clouds require an Apache Zookeeper to connect to.

The Solr operator gives a few options.

#### ZK Connection Info

This is an external/internal connection string as well as an optional chRoot to an already running Zookeeeper ensemble.
If you provide an external connection string, you do not _have_ to provide an internal one as well.

#### Provided Instance

If you do not require the Solr cloud to run cross-kube cluster, and do not want to manage your own Zookeeper ensemble,
the solr-operator can manage Zookeeper ensemble(s) for you.

##### Zookeeper

Using the [zookeeper-operator](https://github.com/pravega/zookeeper-operator), a new Zookeeper ensemble can be spun up for
each solrCloud that has this option specified.

The startup parameter `zookeeper-operator` must be provided on startup of the solr-operator for this parameter to be available.

##### Zetcd

Using [etcd-operator](https://github.com/coreos/etcd-operator), a new Etcd ensemble can be spun up for each solrCloud that has this option specified.
A [Zetcd](https://github.com/etcd-io/zetcd) deployment is also created so that Solr can interact with Etcd as if it were a Zookeeper ensemble.

The startup parameter `etcd-operator` must be provided on startup of the solr-operator for this parameter to be available.

## Solr Backups

Solr backups require 3 things:
Expand Down Expand Up @@ -388,12 +402,16 @@ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/mast
5. Navigate to your browser: http://default-example-solrcloud.ing.local.domain/solr/#/ to validate everything is working


## Version Compatability & Changes
## Version Compatibility & Upgrade Notes

#### v0.2.1
- The zkConnectionString used for provided zookeepers changed from using the string provided in the `ZkCluster.Status`, which used an IP, to using the service name. This will cause a rolling restart of your solrs using the provided zookeeper option, but there will be no data loss.

#### v0.2.0
- Uses `gomod` instead of `dep`
- `SolrCloud.zookeeperRef.provided.zookeeper.persistentVolumeClaimSpec` has been deprecated in favor of the `SolrCloud.zookeeperRef.provided.zookeeper.persistence` option.
This option is backwards compatible, but will be removed in a future version.
- An upgrade to the ZKOperator version `0.2.4` is required.

#### v0.1.1
- `SolrCloud.Spec.persistentVolumeClaim` was renamed to `SolrCloud.Spec.dataPvcSpec`
Expand Down
18 changes: 14 additions & 4 deletions api/v1beta1/solrcloud_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,10 +264,8 @@ func (ref *ZookeeperRef) withDefaults() (changed bool) {

func (ci *ZookeeperConnectionInfo) withDefaults() (changed bool) {
if ci.InternalConnectionString == "" {
changed = true
if ci.ExternalConnectionString == nil {
ci.InternalConnectionString = "N/A"
} else {
if ci.ExternalConnectionString != nil {
changed = true
ci.InternalConnectionString = *ci.ExternalConnectionString
}
}
Expand Down Expand Up @@ -296,6 +294,10 @@ type ProvidedZookeeper struct {
// - An etcd operator to be running
// +optional
Zetcd *FullZetcdSpec `json:"zetcd,inline"`

// The ChRoot to connect solr at
// +optional
ChRoot string `json:"chroot,omitempty"`
}

func (z *ProvidedZookeeper) withDefaults() (changed bool) {
Expand All @@ -309,6 +311,14 @@ func (z *ProvidedZookeeper) withDefaults() (changed bool) {
if z.Zetcd != nil {
changed = z.Zetcd.withDefaults() || changed
}

if z.ChRoot == "" {
changed = true
z.ChRoot = "/"
} else if !strings.HasPrefix(z.ChRoot, "/") {
changed = true
z.ChRoot = "/" + z.ChRoot
}
return changed
}

Expand Down
3 changes: 3 additions & 0 deletions config/crd/bases/solr.bloomberg.com_solrclouds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2040,6 +2040,9 @@ spec:
description: 'A zookeeper that is created by the solr operator Note:
This option will not allow the SolrCloud to run across kube-clusters.'
properties:
chroot:
description: The ChRoot to connect solr at
type: string
etcdSpec:
description: EtcdSpec defines the internal etcd ensemble to
run for solr (spoofing zookeeper)
Expand Down
56 changes: 56 additions & 0 deletions controllers/controller_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@ limitations under the License.
package controllers

import (
solr "github.com/bloomberg/solr-operator/api/v1beta1"
"github.com/onsi/gomega"
"github.com/stretchr/testify/assert"
"golang.org/x/net/context"
appsv1 "k8s.io/api/apps/v1"
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
extv1 "k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"testing"
)
Expand All @@ -49,6 +53,12 @@ func expectStatefulSet(t *testing.T, g *gomega.GomegaWithT, requests chan reconc
return stateful
}

func expectNoStatefulSet(g *gomega.GomegaWithT, statefulSetKey types.NamespacedName) {
stateful := &appsv1.StatefulSet{}
g.Eventually(func() error { return testClient.Get(context.TODO(), statefulSetKey, stateful) }, timeout).
Should(gomega.MatchError("StatefulSet.apps \"" + statefulSetKey.Name + "\" not found"))
}

func expectService(t *testing.T, g *gomega.GomegaWithT, requests chan reconcile.Request, expectedRequest reconcile.Request, serviceKey types.NamespacedName, selectorLables map[string]string) *corev1.Service {
service := &corev1.Service{}
g.Eventually(func() error { return testClient.Get(context.TODO(), serviceKey, service) }, timeout).
Expand Down Expand Up @@ -150,3 +160,49 @@ func expectDeployment(t *testing.T, g *gomega.GomegaWithT, requests chan reconci

return deploy
}

func testPodEnvVariables(t *testing.T, expectedEnvVars map[string]string, foundEnvVars []corev1.EnvVar) {
matchCount := 0
for _, envVar := range foundEnvVars {
if expectedVal, match := expectedEnvVars[envVar.Name]; match {
matchCount += 1
assert.Equal(t, expectedVal, envVar.Value, "Wrong value for env variable '%s' in podSpec", envVar.Name)
}
}
assert.Equal(t, len(expectedEnvVars), matchCount, "Not all expected env variables found in podSpec")
}

func cleanupTest(g *gomega.GomegaWithT, namespace string) {
deleteOpts := []client.DeleteAllOfOption{
client.InNamespace(namespace),
}

cleanupObjects := []runtime.Object{
// Solr Operator CRDs, modify this list whenever CRDs are added/deleted
&solr.SolrCloud{}, &solr.SolrBackup{}, &solr.SolrCollection{}, &solr.SolrCollectionAlias{}, &solr.SolrPrometheusExporter{},

// All dependent Kubernetes types, in order of dependence (deployment then replicaSet then pod)
&corev1.ConfigMap{}, &batchv1.Job{}, &extv1.Ingress{},
&corev1.PersistentVolumeClaim{}, &corev1.PersistentVolume{},
&appsv1.StatefulSet{}, &appsv1.Deployment{}, &appsv1.ReplicaSet{}, &corev1.Pod{},
}
cleanupTestObjects(g, namespace, deleteOpts, cleanupObjects)

// Delete all Services separately (https://github.com/kubernetes/kubernetes/pull/85802#issuecomment-561239845)
opts := []client.ListOption{
client.InNamespace(namespace),
}
services := &corev1.ServiceList{}
g.Eventually(func() error { return testClient.List(context.TODO(), services, opts...) }, timeout).Should(gomega.Succeed())

for _, item := range services.Items {
g.Eventually(func() error { return testClient.Delete(context.TODO(), &item) }, timeout).Should(gomega.Succeed())
}
}

func cleanupTestObjects(g *gomega.GomegaWithT, namespace string, deleteOpts []client.DeleteAllOfOption, objects []runtime.Object) {
// Delete all SolrClouds
for _, obj := range objects {
g.Eventually(func() error { return testClient.DeleteAllOf(context.TODO(), obj, deleteOpts...) }, timeout).Should(gomega.Succeed())
}
}
Loading

0 comments on commit 01f2411

Please sign in to comment.