...

Source file src/edge-infra.dev/pkg/edge/datasync/controllers/couchctl/substitutions_test.go

Documentation: edge-infra.dev/pkg/edge/datasync/controllers/couchctl

     1  package couchctl
     2  
     3  import (
     4  	"testing"
     5  
     6  	appsv1 "k8s.io/api/apps/v1"
     7  	corev1 "k8s.io/api/core/v1"
     8  	"sigs.k8s.io/yaml"
     9  
    10  	"edge-infra.dev/pkg/edge/apis/meta"
    11  	persistenceApi "edge-infra.dev/pkg/edge/apis/persistence/v1alpha1"
    12  	"edge-infra.dev/pkg/edge/controllers/envctl/pkg/nameutils"
    13  	dsapi "edge-infra.dev/pkg/edge/datasync/apis/v1alpha1"
    14  	"edge-infra.dev/pkg/edge/datasync/couchdb"
    15  	"edge-infra.dev/pkg/k8s/unstructured"
    16  	v1ien "edge-infra.dev/pkg/sds/ien/k8s/apis/v1"
    17  	nodemeta "edge-infra.dev/pkg/sds/ien/node"
    18  
    19  	"github.com/stretchr/testify/assert"
    20  )
    21  
    22  var (
    23  	replSet = `apiVersion: datasync.edge.ncr.com/v1alpha1
    24  kind: CouchDBReplicationSet
    25  metadata:
    26    name: "{server_name}"
    27    namespace: data-sync-couchdb
    28  spec:
    29    datasets:
    30    - name: "{replication_db}"
    31      config:
    32        doc_ids:
    33        - repl_doc
    34      provider:
    35        name: ""
    36    source:
    37      name: "{node_uid}"
    38      namespace: "{replication_secret_ns}"
    39    target:
    40      name: "{server_name}"
    41      namespace: data-sync-couchdb
    42  `
    43  	replSetInvalid = `apiVersion: datasync.edge.ncr.com/v1alpha1
    44  kind: CouchDBReplicationSet
    45  metadata:
    46    name: "{anything_goes}"
    47    namespace: data-sync-couchdb
    48  `
    49  	statefulSetTemplate = `apiVersion: datasync.edge.ncr.com/v1alpha1
    50  kind: CouchDBPersistence
    51  metadata:
    52    name: couchdb-lane
    53  spec:
    54    statefulsets:
    55      - apiVersion: apps/v1
    56        kind: StatefulSet
    57        metadata:
    58          name: "{couchdb_sts}"
    59          namespace: data-sync-couchdb
    60          labels:
    61            platform.edge.ncr.com/component: data-sync-couchdb
    62        spec:
    63          replicas: 1
    64          selector:
    65            matchLabels:
    66              platform.edge.ncr.com/component: data-sync-couchdb
    67          template:
    68            metadata:
    69              labels:
    70                platform.edge.ncr.com/component: data-sync-couchdb
    71            spec:
    72              containers:
    73                - name: nignx
    74                  image: nginx
    75              volumes:
    76                - name: config
    77                  configMap:
    78                    name: "{couchdb_sts}"
    79                    items:
    80                      - key: inifile
    81                        path: chart.ini
    82          volumeClaimTemplates:
    83            - metadata:
    84                name: database-storage
    85                labels:
    86                  platform.edge.ncr.com/component: data-sync-couchdb
    87              spec:
    88                resources:
    89                  requests:
    90                    storage: "10Gi"
    91                accessModes:
    92                  - "ReadWriteOnce"
    93          serviceName: data-sync-couchdb
    94          podManagementPolicy: Parallel
    95  `
    96  	rdb = "repl-hash-banner-id"
    97  )
    98  
    99  func TestParseSubstitutions(t *testing.T) {
   100  	substitutions, err := ParseSubstitutions(replSet)
   101  	assert.NoError(t, err)
   102  	assert.Equal(t, len(substitutions), 4) // unique substitutions
   103  
   104  	substitutions, err = ParseSubstitutions(replSetInvalid)
   105  	assert.Error(t, err)
   106  	assert.Nil(t, substitutions)
   107  }
   108  
   109  func TestApplySubstitutions(t *testing.T) {
   110  	suVars := map[SubstitutionVar]string{
   111  		ServerName:          couchdb.StoreServerName,
   112  		ServerType:          string(dsapi.Store),
   113  		LaneNumber:          "",
   114  		Suffix:              "",
   115  		CouchDBStatefulSet:  couchdb.Namespace,
   116  		ChirpName:           ChirpOldName,
   117  		ReplicationDB:       "repl-db",
   118  		ReplicationSecret:   couchdb.StoreReplicationSecretName,
   119  		ReplicationSecretNS: ControllerNamespace,
   120  		NodeUID:             "uid",
   121  	}
   122  	su := ToSubstitution(suVars)
   123  
   124  	r := &dsapi.CouchDBReplicationSet{}
   125  	assert.NoError(t, yaml.Unmarshal([]byte(replSet), r))
   126  	un, err := ApplySubstitutions(r, su)
   127  	assert.NoError(t, err)
   128  	assert.NotNil(t, un)
   129  	assert.NoError(t, unstructured.FromUnstructured(un, r))
   130  	assert.Equal(t, r.Name, couchdb.StoreServerName)
   131  	assert.Equal(t, r.Spec.Datasets[0].Name, "repl-db")
   132  	assert.Equal(t, r.Spec.Source.Name, "uid")
   133  	assert.Equal(t, r.Spec.Source.Namespace, ControllerNamespace)
   134  	assert.Equal(t, r.Spec.Target.Name, couchdb.StoreServerName)
   135  	assert.Equal(t, r.Labels[couchdb.SubstitutionLabel], "true")
   136  }
   137  
   138  func TestStoreSubstitution(t *testing.T) {
   139  	// mostly static variables
   140  	su := StoreSubstitution(rdb)
   141  	assert.Equal(t, su.ServerName, couchdb.StoreServerName)
   142  	assert.Equal(t, su.ServerType, dsapi.Store)
   143  	assert.Equal(t, su.LaneNumber, "")
   144  	assert.Equal(t, su.CouchDBStatefulSet, couchdb.Namespace)
   145  	assert.Equal(t, su.ChirpStatefulSet, ChirpOldName)
   146  	assert.Equal(t, su.ReplicationDB, rdb)
   147  	assert.Equal(t, su.ReplicationSecret, couchdb.StoreReplicationSecretName)
   148  	assert.Equal(t, su.ReplicationSecretNS, ControllerNamespace)
   149  }
   150  
   151  func TestLaneSubstitution(t *testing.T) {
   152  	ni := &nameutils.NodeInfo{
   153  		UID:      "leader-uid",
   154  		Hostname: defaultHost,
   155  		Lane:     "",
   156  		Class:    v1ien.Server,
   157  		Role:     v1ien.ControlPlane,
   158  	}
   159  	su := LaneSubstitution(ni, nil, rdb, "leader-uid")
   160  	assert.True(t, su.Leader)
   161  	assert.Equal(t, su.NodeInfo, ni)
   162  	assert.Equal(t, su.ServerName, "couchdb-leader-uid")
   163  	assert.Equal(t, su.ServerType, dsapi.Store)
   164  	assert.Equal(t, su.LaneNumber, "")
   165  	assert.Equal(t, su.CouchDBStatefulSet, "couchdb-"+meta.Hash("leader-uid"))
   166  	assert.Equal(t, su.ChirpStatefulSet, "chirp-"+meta.Hash("leader-uid"))
   167  	assert.Equal(t, su.ReplicationDB, rdb)
   168  	assert.Equal(t, su.ReplicationSecret, couchdb.StoreReplicationSecretName)
   169  	assert.Equal(t, su.ReplicationSecretNS, ControllerNamespace)
   170  	assert.Equal(t, su.NodeUID, "leader-uid")
   171  
   172  	ni = &nameutils.NodeInfo{
   173  		UID:      "uid",
   174  		Name:     "test",
   175  		Hostname: "ien",
   176  		Lane:     "1",
   177  		Class:    v1ien.Touchpoint,
   178  		Role:     v1ien.Worker,
   179  	}
   180  	m := map[string]map[string]string{}
   181  	m["data-sync-couchdb"] = map[string]string{
   182  		"test": "1",
   183  	}
   184  	m["data-sync-messaging"] = map[string]string{
   185  		"test": "1",
   186  	}
   187  
   188  	// old pvc prefix
   189  	su = LaneSubstitution(ni, m, rdb, "leader-uid")
   190  	assert.False(t, su.Leader)
   191  	assert.Equal(t, su.NodeInfo, ni)
   192  	assert.Equal(t, su.ServerName, "couchdb-uid")
   193  	assert.Equal(t, su.ServerType, dsapi.Touchpoint)
   194  	assert.Equal(t, su.LaneNumber, "1")
   195  	assert.Equal(t, su.CouchDBStatefulSet, "data-sync-couchdb-1")
   196  	assert.Equal(t, su.ChirpStatefulSet, "data-sync-messaging-1")
   197  	assert.Equal(t, su.ReplicationDB, rdb)
   198  	assert.Equal(t, su.ReplicationSecret, "couchdb-leader-uid")
   199  	assert.Equal(t, su.ReplicationSecretNS, couchdb.Namespace)
   200  	assert.Equal(t, su.NodeUID, "uid")
   201  }
   202  
   203  func TestStoreStatefulSetSubstitution(t *testing.T) {
   204  	su := StoreSubstitution(rdb)
   205  
   206  	p := &dsapi.CouchDBPersistence{}
   207  	err := yaml.Unmarshal([]byte(statefulSetTemplate), p)
   208  	assert.NoError(t, err)
   209  	sts := &p.Spec.StatefulSets[0]
   210  
   211  	// Store Server StatefulSet Substitution
   212  	un, err := ApplySubstitutions(sts, su)
   213  	assert.NoError(t, err)
   214  	assert.NotNil(t, un)
   215  
   216  	sts = &appsv1.StatefulSet{}
   217  	err = unstructured.FromUnstructured(un, sts)
   218  	assert.NoError(t, err)
   219  
   220  	assert.Equal(t, sts.Name, su.CouchDBStatefulSet)
   221  	assert.Equal(t, sts.Spec.Selector.MatchLabels[persistenceApi.InstanceLabel], sts.Name)
   222  	assert.Equal(t, sts.Spec.Template.ObjectMeta.Labels[persistenceApi.InstanceLabel], sts.Name)
   223  	assert.NotContains(t, sts.Spec.Template.ObjectMeta.Labels, nodemeta.ClassLabel)
   224  	assert.Equal(t, sts.Spec.Template.Spec.Volumes[0].ConfigMap.Name, su.CouchDBStatefulSet)
   225  
   226  	na := sts.Spec.Template.Spec.Affinity.NodeAffinity
   227  
   228  	assert.Nil(t, na.RequiredDuringSchedulingIgnoredDuringExecution)
   229  	assert.Len(t, na.PreferredDuringSchedulingIgnoredDuringExecution, 1)
   230  	sch := na.PreferredDuringSchedulingIgnoredDuringExecution[0]
   231  	assert.Equal(t, int32(100), sch.Weight)
   232  	assert.Empty(t, sch.Preference.MatchFields)
   233  	assert.Len(t, sch.Preference.MatchExpressions, 1)
   234  	assert.Equal(t, sch.Preference.MatchExpressions[0], corev1.NodeSelectorRequirement{
   235  		Key:      nodemeta.RoleLabel,
   236  		Operator: corev1.NodeSelectorOpIn,
   237  		Values:   []string{string(v1ien.ControlPlane)},
   238  	})
   239  }
   240  
   241  func TestLaneStatefulSetSubstitution(t *testing.T) {
   242  	ni := &nameutils.NodeInfo{
   243  		UID:      "uid",
   244  		Hostname: defaultHost,
   245  		Lane:     "1",
   246  		Class:    v1ien.Touchpoint,
   247  		Role:     v1ien.Worker,
   248  	}
   249  	su := LaneSubstitution(ni, nil, rdb, "leader-uid")
   250  
   251  	p := &dsapi.CouchDBPersistence{}
   252  	err := yaml.Unmarshal([]byte(statefulSetTemplate), p)
   253  	assert.NoError(t, err)
   254  	sts := &p.Spec.StatefulSets[0]
   255  
   256  	// Lane StatefulSet Substitution
   257  	un, err := ApplySubstitutions(sts, su)
   258  	assert.NoError(t, err)
   259  	assert.NotNil(t, un)
   260  
   261  	sts = &appsv1.StatefulSet{}
   262  	err = unstructured.FromUnstructured(un, sts)
   263  	assert.NoError(t, err)
   264  
   265  	assert.Equal(t, sts.Name, su.CouchDBStatefulSet)
   266  	assert.Equal(t, sts.Labels[couchdb.NodeUIDLabel], "uid")
   267  	assert.Equal(t, sts.Spec.Selector.MatchLabels[persistenceApi.InstanceLabel], sts.Name)
   268  	assert.Equal(t, sts.Spec.Template.ObjectMeta.Labels[persistenceApi.InstanceLabel], sts.Name)
   269  	assert.Equal(t, sts.Spec.Template.Spec.Volumes[0].ConfigMap.Name, su.CouchDBStatefulSet)
   270  
   271  	na := sts.Spec.Template.Spec.Affinity.NodeAffinity
   272  	assert.Nil(t, na.PreferredDuringSchedulingIgnoredDuringExecution)
   273  	assert.NotNil(t, na.RequiredDuringSchedulingIgnoredDuringExecution)
   274  	nodeSelectors := na.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms
   275  
   276  	assert.Len(t, nodeSelectors, 1)
   277  
   278  	nodeSelector := nodeSelectors[0]
   279  	assert.Empty(t, nodeSelector.MatchFields)
   280  	assert.Len(t, nodeSelector.MatchExpressions, 1)
   281  
   282  	assert.Equal(t, nodeSelector.MatchExpressions[0], corev1.NodeSelectorRequirement{
   283  		Key:      couchdb.NodeUIDLabel,
   284  		Operator: corev1.NodeSelectorOpIn,
   285  		Values:   []string{su.NodeUID},
   286  	})
   287  }
   288  

View as plain text