Provisioning Cluster Resources

    +

    Unresolved include directive in modules/howtos/pages/provisioning-cluster-resources.adoc - include::partial$attributes.adoc[]

    Provisioning cluster resources is managed at the collection or bucket level, depending upon the service affected. Common use cases are outlined here, more recherché use cases are covered in the API docs.

    Unresolved directive in provisioning-cluster-resources.adoc - include::{version-server}@sdk:shared:partial$flush-info-pars.adoc[tag=management-intro]

    The Scala SDK also comes with some convenience functionality for common Couchbase management requests.

    Management operations in the SDK may be performed through several interfaces depending on the object:

    val bucketManager: BucketManager = cluster.buckets
    val userManager: UserManager = cluster.users
    val queryIndexManager: QueryIndexManager = cluster.queryIndexes
    val analyticsIndexManager: AnalyticsIndexManager = cluster.analyticsIndexes
    val searchIndexManager: SearchIndexManager = cluster.searchIndexes
    val collectionManager: CollectionManager = bucket.collections
    val viewIndexManager: ViewIndexManager = bucket.viewIndexes
    When using a Couchbase version earlier than 6.5, you must create a valid Bucket connection using cluster.bucket(name) before you can use cluster-level managers.

    Creating and Removing Buckets

    The BucketManager interface may be used to create and delete buckets from the Couchbase cluster.

    The CreateBucketSettings and BucketSettings classes are used for creating and updating buckets. BucketSettings is also used for exposing information about existing buckets.

    Unresolved directive in provisioning-cluster-resources.adoc - include::{version-server}@sdk:shared:partial$flush-info-pars.adoc[tag=update-bucket-warning]

    Here is the list of parameters available for CreateBucketSettings and BucketSettings. The "Updatable" column indicates whether the parameter may only be specified when creating a bucket, or whether it may be updated after creation.

    Name Type Description Updatable

    name

    String

    The name of the bucket, required for creation.

    false

    flushEnabled

    boolean

    Enables flushing to be performed on this bucket (see the Flushing Buckets section below).

    true

    replicaIndexes

    boolean

    Whether or not to replicate indexes.

    false

    ramQuotaMB

    int

    How much memory should each node use for the bucket, required for creation.

    true

    numReplicas

    int

    The number of replicas to use for the bucket.

    true

    bucketType

    BucketType

    The type of the bucket, required for creation.

    false

    ejectionMethod

    EjectionMethod

    The type of the ejection to use for the bucket, defaults to ValueOnly.

    true (note: changing will cause the bucket to restart causing temporary inaccessibility)

    maxTTL

    int

    The default maximum time-to-live to apply to documents in the bucket. (note: This option is only available for Couchbase and Ephemeral buckets in Couchbase Enterprise Edition.)

    true

    compressionMode

    CompressionMode

    The compression mode to apply to documents in the bucket. (note: This option is only available for Couchbase and Ephemeral buckets in Couchbase Enterprise Edition.)

    true

    conflictResolutionType

    ConflictResolutionType

    The conflict resolution type to apply to conflicts on the bucket, defaults to SequenceNumber

    false

    The following example creates a "hello" bucket:

    val bucketManager: BucketManager = cluster.buckets
    
    val result: Try[Unit] = bucketManager.create(
      CreateBucketSettings("hello", ramQuotaMB = 1024)
        .flushEnabled(false)
        .replicaIndexes(false)
        .numReplicas(1)
        .bucketType(BucketType.Couchbase)
        .conflictResolutionType(ConflictResolutionType.SequenceNumber))
    
    result match {
      case Success(_) =>
      case Failure(err) => print(s"Failed with error $err")
    }

    We can now get this bucket and update it to enable Flush:

    val result: Try[Unit] = bucketManager.getBucket("hello")
      .flatMap((bucket: BucketSettings) => {
        val updated = bucket.toCreateBucketSettings.flushEnabled(true)
        bucketManager.updateBucket(updated)
      })
    
    // Result error-checking omitted for brevity

    Once you no longer need to use the bucket, you can remove it:

    val result: Try[Unit] = bucketManager.dropBucket("hello")
    
    // Result error-checking omitted for brevity

    Flushing Buckets

    Unresolved directive in provisioning-cluster-resources.adoc - include::{version-server}@sdk:shared:partial$flush-info-pars.adoc[tag=flush-intro]

    You can flush a bucket in the SDK by using the Flush method:

    val result: Try[Unit] = bucketManager.flushBucket("hello")
    
    result match {
      case Success(_) =>
      case Failure(err: BucketNotFlushableException) =>
        print("Flushing not enabled on this bucket")
      case Failure(err) => print(s"Failed with error $err")
    }

    Collection Management

    The CollectionManager interface may be used to create and delete scopes and collections from the Couchbase cluster. It is instantiated through the Bucket.collections() method. Refer to the CollectionManager and AsyncCollectionManager API documentation for further details.

    val collectionMgr = bucket.collections;

    You can create a scope:

    collectionMgr.createScope("example-scope") match {
      case Success(_) =>
        println("Created scope OK")
      case Failure(err: ScopeExistsException) =>
        println("scope already exists")
      case Failure(err) =>
        println(err)
    }

    You can then create a collection within that scope:

    val spec = CollectionSpec("example-collection", "example-scope");
    
    collectionMgr.createCollection(spec)  match {
      case Success(_) =>
        println("Created collection OK")
      case Failure(err: ScopeNotFoundException) =>
        println("scope not found")
      case Failure(err: CollectionExistsException) =>
        println("collection already exists")
      case Failure(err) =>
        println(err)
    }

    Finally, you can drop unneeded collections and scopes:

    collectionMgr.dropCollection(spec)
    match {
      case Success(_) =>
        println("Dropped collection OK")
      case Failure(err: ScopeNotFoundException) =>
        println("scope not found")
      case Failure(err: CollectionNotFoundException) =>
        println("collection not found")
      case Failure(err) =>
        println(err)
    }
    
    [data-source-url=https://github.com/couchbase/docs-sdk-scala/blob/ad7d57e8c9a15ad51be31a2ea61f18324d3b1b56/modules/howtos/examples/CollectionManagerExample.scala#L110-L118]
    collectionMgr.dropScope("example-scope")
    match {
      case Success(_) =>
        println("Dropped scope OK")
      case Failure(err: ScopeNotFoundException) =>
        println("scope not found")
      case Failure(err) =>
        println(err)
    }

    Note that the most minimal permissions to create and drop a Scope or Collection is Manage Scopes along with Data Reader.

    You can create users with the appropriate RBAC programmatically:

    val users = cluster.users
    val user = User("scopeAdmin")
      .password("password")
      .roles(
        new Role("scope_admin", Some("travel-sample")),
        new Role("data_reader", Some("travel-sample")))
    users.upsertUser(user).get

    Index Management

    In general,you will rarely need to work with Index Managers from the SDK. For those occasions when you do, please see the relevant API docs:

    val queryIndexManager: QueryIndexManager = cluster.queryIndexes
    val analyticsIndexManager: AnalyticsIndexManager = cluster.analyticsIndexes
    val searchIndexManager: SearchIndexManager = cluster.searchIndexes
    val viewIndexManager: ViewIndexManager = bucket.viewIndexes

    View Management

    Unresolved directive in provisioning-cluster-resources.adoc - include::{version-server}@sdk:shared:partial$flush-info-pars.adoc[tag=view-management]

    In the SDK, design documents are represented by the DesignDocument and View structs. All operations on design documents are performed on the ViewIndexManager instance:

    val viewIndexManager: ViewIndexManager = bucket.viewIndexes

    The following example upserts a design document with two views:

    val view1 = View("function (doc, meta) { if (doc.type == 'landmark') { emit([doc.country, doc.city], null); } }")
    val view2 = View("function (doc, meta) { if (doc.type == 'landmark') { emit(doc.activity, null); } }", reduce = Some("_count"))
    
    val designDoc = DesignDocument("landmarks",
      Map("by_country" -> view1, "by_activity " -> view2))
    
    viewIndexManager.upsertDesignDocument(designDoc, DesignDocumentNamespace.Development)

    Unresolved directive in provisioning-cluster-resources.adoc - include::{version-server}@sdk:shared:partial$flush-info-pars.adoc[tag=one-view-update-warning]

    Note the use of DesignDocumentNamespace.Development, the other option is DesignDocumentNamespace.Production. This parameter specifies whether the design document should be created as development, or as production — with the former running over only a small fraction of the documents.

    Now that we’ve created a design document we can fetch it:

    val designDoc: Try[DesignDocument] =
      viewIndexManager.getDesignDocument("landmarks", DesignDocumentNamespace.Development)

    We’ve created the design document using DesignDocumentNamespace.Development and now want to push it to production, we can do this with:

    val publishResult = viewIndexManager.publishDesignDocument("landmarks")
    
    // Result error-handling omitted for brevity

    To remove this design document:

    val dropResult = viewIndexManager.dropDesignDocument("landmarks", DesignDocumentNamespace.Production)
    // Result error-handling omitted for brevity