Skip to content

Commit

Permalink
Persistent volume infinispan#126
Browse files Browse the repository at this point in the history
  • Loading branch information
rigazilla committed Oct 23, 2019
1 parent 7ef600d commit fd43c95
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 13 deletions.
2 changes: 1 addition & 1 deletion doc/design.adoc
Expand Up @@ -91,7 +91,7 @@ This document describes the types introduced by the Infinispan Operator to be co
[[infinispanservicespec]]
#### `InfinispanServiceSpec`

`InfinispanCacheSpec` configures aspects related to the cache or datagrid service.
`InfinispanServiceSpec` configures aspects related to the cache or datagrid service.

[options="header,footer"]
|=======================
Expand Down
12 changes: 12 additions & 0 deletions pkg/apis/infinispan/v1/infinispan_types.go
Expand Up @@ -22,6 +22,17 @@ type EndpointEncryption struct {
CertSecretName string `json:"certSecretName"`
}

// InfinispanServiceContainerSpec resource requirements specific for service
type InfinispanServiceContainerSpec struct {
Storage string `json:"storage"`
}

// InfinispanServiceSpec specify configuration for specific service
type InfinispanServiceSpec struct {
Type string `json:"type"`
Container InfinispanServiceContainerSpec `json:"container"`
}

// InfinispanContainerSpec specify resource requirements per container
type InfinispanContainerSpec struct {
ExtraJvmOpts string `json:"extraJvmOpts"`
Expand All @@ -35,6 +46,7 @@ type InfinispanSpec struct {
Image string `json:"image"`
Security InfinispanSecurity `json:"security"`
Container InfinispanContainerSpec `json:"container"`
Service InfinispanServiceSpec `json:"service"`
}

// InfinispanCondition define a condition of the cluster
Expand Down
34 changes: 34 additions & 0 deletions pkg/apis/infinispan/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 40 additions & 4 deletions pkg/controller/infinispan/infinispan_controller.go
Expand Up @@ -36,6 +36,9 @@ var log = logf.Log.WithName("controller_infinispan")
// DefaultImageName is used if a specific image name is not provided
var DefaultImageName = getEnvWithDefault("DEFAULT_IMAGE", "registry.hub.docker.com/infinispan/server")

// DefaultPVSize default size for persistent volume
var DefaultPVSize = resource.MustParse("1Gi")

// Kubernetes object
var kubernetes *ispnutil.Kubernetes

Expand Down Expand Up @@ -148,7 +151,11 @@ func (r *ReconcileInfinispan) Reconcile(request reconcile.Request) (reconcile.Re
}

// Define a new deployment
dep := r.deploymentForInfinispan(infinispan, secret, configMap)
dep, err := r.deploymentForInfinispan(infinispan, secret, configMap)
if err != nil {
reqLogger.Error(err, "failed to configure new Deployment", "Deployment.Namespace", dep.Namespace, "Deployment.Name", dep.Name)
return reconcile.Result{}, err
}
reqLogger.Info("Creating a new Deployment", "Deployment.Namespace", dep.Namespace, "Deployment.Name", dep.Name)
err = r.client.Create(context.TODO(), dep)
if err != nil {
Expand Down Expand Up @@ -323,7 +330,7 @@ func (r *ReconcileInfinispan) Reconcile(request reconcile.Request) (reconcile.Re
}

// deploymentForInfinispan returns an infinispan Deployment object
func (r *ReconcileInfinispan) deploymentForInfinispan(m *infinispanv1.Infinispan, secret *corev1.Secret, configMap *corev1.ConfigMap) *appsv1beta1.StatefulSet {
func (r *ReconcileInfinispan) deploymentForInfinispan(m *infinispanv1.Infinispan, secret *corev1.Secret, configMap *corev1.ConfigMap) (*appsv1beta1.StatefulSet, error) {
// This field specifies the flavor of the
// Infinispan cluster. "" is plain community edition (vanilla)
ls := labelsForInfinispan(m.ObjectMeta.Name)
Expand Down Expand Up @@ -367,7 +374,7 @@ func (r *ReconcileInfinispan) deploymentForInfinispan(m *infinispanv1.Infinispan
}
}
}

replicas := m.Spec.Replicas
dep := &appsv1beta1.StatefulSet{

TypeMeta: metav1.TypeMeta{
Expand All @@ -389,6 +396,7 @@ func (r *ReconcileInfinispan) deploymentForInfinispan(m *infinispanv1.Infinispan
Selector: &metav1.LabelSelector{
MatchLabels: ls,
},
Replicas: &replicas,
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: ls,
Expand Down Expand Up @@ -446,12 +454,40 @@ func (r *ReconcileInfinispan) deploymentForInfinispan(m *infinispanv1.Infinispan
},
},
}
pvSize := DefaultPVSize
if m.Spec.Service.Type == "Data Grid" && m.Spec.Service.Container.Storage != "" {
var pvErr error
pvSize, pvErr = resource.ParseQuantity(m.Spec.Service.Container.Storage)
if pvErr != nil {
return nil, pvErr
}
}
dep.Spec.VolumeClaimTemplates = []corev1.PersistentVolumeClaim{{
ObjectMeta: metav1.ObjectMeta{
Name: m.ObjectMeta.Name,
Namespace: m.ObjectMeta.Namespace,
},
Spec: corev1.PersistentVolumeClaimSpec{
AccessModes: []corev1.PersistentVolumeAccessMode{
"ReadWriteOnce",
},
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: pvSize,
},
},
}}}
v := &dep.Spec.Template.Spec.Containers[0].VolumeMounts
*v = append(*v, corev1.VolumeMount{
Name: m.ObjectMeta.Name,
MountPath: "/opt/infinispan/server/data",
})
setupVolumesForEncryption(m, dep)
// appendVolumes(m, dep)

// Set Infinispan instance as the owner and controller
controllerutil.SetControllerReference(m, dep, r.scheme)
return dep
return dep, nil
}

func getEncryptionSecretName(m *infinispanv1.Infinispan) string {
Expand Down
83 changes: 75 additions & 8 deletions test/e2e/main_test.go
Expand Up @@ -35,6 +35,8 @@ var Memory = getEnvWithDefault("INFINISPAN_MEMORY", "512Mi")
var kubernetes = testutil.NewTestKubernetes()
var cluster = util.NewCluster(kubernetes.Kubernetes)

var DefaultClusterName = "test-node-startup"

func TestMain(m *testing.M) {
namespace := strings.ToLower(Namespace)
kubernetes.DeleteNamespace(namespace)
Expand All @@ -52,7 +54,6 @@ func TestSimple(t *testing.T) {
fmt.Printf("%s\n", kubernetes.PublicIP())
}

var DefaultClusterName = "test-node-startup"
var DefaultSpec = ispnv1.Infinispan{
TypeMeta: metav1.TypeMeta{
APIVersion: "infinispan.org/v1",
Expand Down Expand Up @@ -241,6 +242,69 @@ func genericTestForContainerUpdated(modifier func(*ispnv1.Infinispan), verifier
verifier(&ss)
}

// TestPermanentCache creates a permanent caches the stop/start
// the cluster and checks that the cache is still there
func TestPermanentCache(t *testing.T) {
name := "test-permament-cache"
usr := "developer"
cacheName := "test"
// Define function for the generic stop/start test procedure
var createPermanentCache = func(ispn *ispnv1.Infinispan) {
pass, err := cluster.GetPassword(usr, util.GetSecretName(name), Namespace)
testutil.ExpectNoError(err)
routeName := fmt.Sprintf("%s-external", name)
client := &http.Client{}
hostAddr := kubernetes.WaitForExternalService(routeName, RouteTimeout, client, Namespace)
createCache(cacheName, usr, pass, hostAddr, "PERMANENT", client)
}

var usePermanentCache = func(ispn *ispnv1.Infinispan) {
pass, err := cluster.GetPassword(usr, util.GetSecretName(name), Namespace)
testutil.ExpectNoError(err)
routeName := fmt.Sprintf("%s-external", name)
client := &http.Client{}
hostAddr := kubernetes.WaitForExternalService(routeName, RouteTimeout, client, Namespace)
key := "test"
value := "test-operator"
keyURL := fmt.Sprintf("%v/%v", cacheURL(cacheName, hostAddr), key)
putViaRoute(keyURL, value, client, usr, pass)
actual := getViaRoute(keyURL, client, usr, pass)
if actual != value {
panic(fmt.Errorf("unexpected actual returned: %v (value %v)", actual, value))
}
deleteCache(cacheName, usr, pass, hostAddr, client)
}

genericTestForPersistenceVolume(name, createPermanentCache, usePermanentCache)
}

// Test if single node working correctly
func genericTestForPersistenceVolume(clusterName string, modifier func(*ispnv1.Infinispan), verifier func(*ispnv1.Infinispan)) {
// Create a resource without passing any config
// Register it
spec := DefaultSpec.DeepCopy()
spec.ObjectMeta.Name = clusterName
kubernetes.CreateInfinispan(spec, Namespace)
defer kubernetes.DeleteInfinispan(spec, SinglePodTimeout)
waitForPodsOrFail(clusterName, "http", 1)

// Do something that needs to be permanent
modifier(spec)

// Delete the cluster
kubernetes.DeleteInfinispan(spec, SinglePodTimeout)

// Restart cluster
spec = DefaultSpec.DeepCopy()
spec.ObjectMeta.Name = clusterName
kubernetes.CreateInfinispan(spec, Namespace)

waitForPodsOrFail(clusterName, "http", 1)

// Do something that checks that permanent changes are there again
verifier(spec)
}

func waitForPodsOrFail(name, protocol string, num int) {
// Wait that "num" pods are up
kubernetes.WaitForPods("app=infinispan-pod", num, SinglePodTimeout, Namespace)
Expand Down Expand Up @@ -311,7 +375,7 @@ func TestExternalService(t *testing.T) {
hostAddr := kubernetes.WaitForExternalService(routeName, RouteTimeout, client, usr, pass, Namespace)

cacheName := "test"
createCache(cacheName, usr, pass, hostAddr, client)
createCache(cacheName, usr, pass, hostAddr, "", client)
defer deleteCache(cacheName, usr, pass, hostAddr, client)

key := "test"
Expand Down Expand Up @@ -408,7 +472,7 @@ func testAuthentication(name, usr, pass string) {

cacheName := "test"
createCacheBadCreds(cacheName, "badUser", "badPass", hostAddr, client)
createCache(cacheName, usr, pass, hostAddr, client)
createCache(cacheName, usr, pass, hostAddr, "", client)
defer deleteCache(cacheName, usr, pass, hostAddr, client)

key := "test"
Expand All @@ -434,10 +498,10 @@ func (e *httpError) Error() string {
return fmt.Sprintf("unexpected response %v", e.status)
}

func createCache(cacheName, usr, pass, hostAddr string, client *http.Client) {
func createCache(cacheName, usr, pass, hostAddr string, flags string, client *http.Client) {
httpURL := cacheURL(cacheName, hostAddr)
fmt.Printf("Create cache: %v\n", httpURL)
httpEmpty(httpURL, "POST", usr, pass, client)
httpEmpty(httpURL, "POST", usr, pass, flags, client)
}

func createCacheBadCreds(cacheName, usr, pass, hostAddr string, client *http.Client) {
Expand All @@ -451,17 +515,20 @@ func createCacheBadCreds(cacheName, usr, pass, hostAddr string, client *http.Cli
panic(err)
}
}()
createCache(cacheName, usr, pass, hostAddr, client)
createCache(cacheName, usr, pass, hostAddr, "", client)
}

func deleteCache(cacheName, usr, pass, hostAddr string, client *http.Client) {
httpURL := cacheURL(cacheName, hostAddr)
fmt.Printf("Delete cache: %v\n", httpURL)
httpEmpty(httpURL, "DELETE", usr, pass, client)
httpEmpty(httpURL, "DELETE", usr, pass, "", client)
}

func httpEmpty(httpURL string, method string, usr string, pass string, client *http.Client) {
func httpEmpty(httpURL string, method string, usr string, pass string, flags string, client *http.Client) {
req, err := http.NewRequest(method, httpURL, nil)
if flags != "" {
req.Header.Set("flags", flags)
}
testutil.ExpectNoError(err)

req.SetBasicAuth(usr, pass)
Expand Down

0 comments on commit fd43c95

Please sign in to comment.