Difference between revisions of "PEC-REP/Current/GIMPEGuide/ConfigureGSP"

From Genesys Documentation
Jump to: navigation, search
m (Text replacement - "Genesys Engage [cC]loud" to "Genesys Multicloud CX")
 
(9 intermediate revisions by the same user not shown)
Line 5: Line 5:
 
|ComingSoon=No
 
|ComingSoon=No
 
|Section={{Section
 
|Section={{Section
|sectionHeading=Create an Object Bucket Claim
+
|sectionHeading=GSP Helm chart overrides
|anchor=S3
+
|anchor=GSP_HelmCharts
 
|alignment=Vertical
 
|alignment=Vertical
|structuredtext=To enable storage of data during GSP processing, create an S3 Object Bucket Claim (OBC) if none exists.
+
|structuredtext=The GSP requires some configuration for deployment that must be made by modifying the GSP's default Helm chart. You do this by creating override entries in the GSP's '''values.yaml''' file.
  
See the '''gsp-obc.yaml''' file:
+
Download the GSP Helm charts from your image registry, using the appropriate credentials.  
<source lang="bash">apiVersion: objectbucket.io/v1alpha1
 
kind: ObjectBucketClaim
 
metadata:
 
  name: gim
 
  namespace: gsp
 
spec:
 
  generateBucketName: gim
 
  storageClassName: openshift-storage.noobaa.io</source>
 
  
Then execute the command to create the OBC:
+
For information about how to download the Helm charts, see {{SuiteLevelLink|helmchart}}. To find the correct Helm chart version for your release, see {{Link-AnywhereElse|product=ReleaseNotes|version=Current|manual=GenesysEngage-cloud|topic=GIMHelm}} for the Helm chart version you must download for your release. For general information about Helm chart overrides, see {{SuiteLevelLink|helmoverride}} in the ''{{Link-AnywhereElse|product=PrivateEdition|version=Current|manual=PEGuide|display text=Genesys Multicloud CX Private Edition Guide}}''.
  
<source lang="text">oc create -f gsp-obc.yaml -n gsp</source>
+
At minimum, you must create entries in the '''values.yaml''' file to specify key system information, as described in the following sections.
  
The following Kubernetes resources are created automatically:
+
{{NoteFormat|Treat your modified '''values.yaml''' file as source code, which you are responsible to maintain so that your overrides are preserved and available for reuse when you upgrade.}}
 +
|Status=No
 +
}}{{Section
 +
|sectionHeading=Image registry and pull secret
 +
|anchor=GSP_Config_ImagePull
 +
|alignment=Vertical
 +
|structuredtext={{AnchorDiv|GSP_ImageRegistry}}
 +
===Image registry===
 +
Create an entry in the GSP's '''values.yaml''' file to specify the location of your image registry. This is the repository from which Kubernetes pulls images.
  
*An ObjectBucket (OB), which contains the bucket endpoint information, a reference to the OBC, and a reference to the storage class.
+
The location of the image registry is defined when you set up the environment for the GSP. It is represented in the system as the <code>docker-registry</code>. In the GSP Helm chart, the repository is represented as <code>image: registry</code>, as shown in the following example.  You can optionally set a container version for the image, as in the following example.
*A ConfigMap in the same namespace as the OBC, which contains the endpoint to which applications connect in order to consume the object interface
 
*A Secret in the same namespace as the OBC, which contains the key-pairs needed to access the bucket.
 
  
Note the following:
+
<source lang="bash">
 +
image: # The repository from which Kubernetes pulls images
 +
  registry: <your_container_registry>  # The default registry is pureengage-docker-staging.jfrog.io
 +
  tag: <image_tag> # The container image tag/version
 +
</source>
  
*The name of the secret and the configMap are the same as the OBC name.
+
{{AnchorDiv|GSP_Config_PullSecret}}
*The bucket name is created with a randomized suffix.
+
===Pull secret===
 +
When you set up your environment, you define a pull secret for the image registry (<code>docker-registry</code>). You must include the pull secret in the GSP's '''values.yaml''' file in order for Kubernetes to be able to pull from the repository.
  
{{AnchorDiv|S3Data}}
+
<source lang="bash">
===Get S3 data===
+
imagePullSecrets:
You need to know details of your S3 object to populate Helm chart override values for GSP and GCA.
+
  docker-registry: {<pull-secret>} # The credentials Kubernetes will use to pull the image from the registry
 +
</source>
  
To get the OBC data, execute the following command, where <tt>gim</tt> is the name of the configMap associated with the OBC:
+
Note that other services use a different syntax than this to configure the repository pull secret, as follows:
<source lang="text">oc get cm gim -n gsp -o yaml -o jsonpath={.data}</source>
+
<source lang="bash">
 +
imagePullSecrets:
 +
  name: docker-registry
 +
</source>
 +
Genesys Info Mart, GIM Stream Processor, and GIM Configuration Adaptor helm charts all support advanced templating that allow the helm to create the pull secret automatically; hence the variation in syntax.
 +
|Status=No
 +
}}{{Section
 +
|sectionHeading=Kafka
 +
|anchor=GSP_Kafka_Configuration
 +
|alignment=Vertical
 +
|structuredtext={{AnchorDiv|GSP_KafkaSecret}}
  
The result shows data such as BUCKET_HOST, BUCKET_NAME, BUCKET_PORT, and so on.
+
===Kafka secret===
 +
If Kafka is configured with authentication, you must configure the Kafka secret so GSP can access Kafka. The Kafka secret is provisioned in the system as <code>kafka-secrets</code> when you set up the environment for GSP. Configure the Kafka secret by creating a Helm chart override in the '''values.yaml''' file.
  
Execute the following commands to get the values of the keys you require for access, where <tt>gim</tt> is the name of the secret associated with the OBC:
+
<source lang="bash">
 +
kafka:
 +
  password: <kafka-password> # Credentials for accessing Kafka. This secret is created during deployment.
 +
</source>
 +
 
 +
{{AnchorDiv|GSP_KafkaBootstrap}}
 +
===Kafka bootstrap===
 +
To allow the Kafka service on GSP to align with the infrastructure Kafka service, make a Helm override entry with the location of the Kafka bootstrap.
  
*To get the value of the access key:
+
<source lang="bash">kafka:
*:<source lang="text">oc get secret gim -n gsp -o yaml -o jsonpath={.data.AWS_ACCESS_KEY_ID} | base64 --decode</source>
+
  bootstrap: <kafka-bootstrap-location> # The Kafka address to align with the infrastructure Kafka
*To get the value of the secret key:
+
</source>
*:<source lang="text">oc get secret gim -n gsp -o yaml -o jsonpath={.data.AWS_SECRET_ACCESS_KEY} | base64 --decode</source>
 
  
Use the S3 data to populate the Helm chart override values for GSP and GCA.
+
{{AnchorDiv|GSP_Config_KafkaTopics}}
 +
===Custom Kafka topic names===
 +
Some of the Kafka topics used by the GSP support customizing the topic name. If any topic name has been customized, ensure it is represented as a Helm chart override entry, using the <code>kafka:topic</code>  parameter.
  
{{NoteFormat|You can also obtain the S3 data from the OpenShift console: Go to the '''Object bucket claims''' section under the '''Storage''' menu, and click on the required OBC resource. The data will be at the bottom of the page.|2}}
+
For a list of the Kafka topics that GSP produces and consumes, including which of those support customized naming, see {{Link-AnywhereElse|product=PEC-REP|version=Current|manual=GIMPEGuide|topic=PlanningGSP|anchor=GSP_KafkaTopics}}.
 
|Status=No
 
|Status=No
 
}}{{Section
 
}}{{Section
|sectionHeading=Override Helm chart values
+
|sectionHeading=S3-compatible storage
 +
|anchor=GSP_S3Storage
 
|alignment=Vertical
 
|alignment=Vertical
|structuredtext=Download the GSP Helm charts from JFrog using your credentials. You must override certain parameters in the GSP '''values.yaml''' file to provide deployment-specific values for certain parameters.
+
|structuredtext={{AnchorDiv|GSP_Config_KafkaBootstrap}}
 +
===S3 storage credentials===
 +
When you set up the environment for GSP, you provision S3-compatible object storage for GSP to use as a persistent data store. In the '''values.yaml''' file, record the credentials needed by GSP to access this storage.
  
For general information about overriding Helm chart values, see {{SuiteLevelLink|helmoverride}} in the ''{{Link-AnywhereElse|product=PrivateEdition|version=Current|manual=PEGuide|display text=Genesys Multicloud CX Private Edition Guide}}''.
+
<source lang="bash">
 +
gsp-s3: <s3-credentials> # Credentials for accessing S3-compatible storage
 +
</source>
  
If you want to use arbitrary UIDs in your OpenShift deployment, you must override the '''securityContext''' settings in the GSP '''values.yaml''' file, so that no user or group IDs are specified. For details, see [[{{FULLPAGENAME}}#Security|Configure security]], below.
+
{{AnchorDiv|GSP_Config_KafkaBootstrap}}
 +
===Enable S3-compatible storage===
 +
When you set up your environment for the GSP, you provision S3-compatible object storage for the GSP's persistent data store. You must enable this storage with override entries in the '''values.yaml''' file.
  
At a minimum, you must override the following key entries in the GSP '''values.yaml''' file:
+
By default, GSP is configured to use Azure Blob Storage as the persistent data store. If you have provisioned Azure Blob Storage in your deployment, modify the following entries in the '''values.yaml''' file:
  
*<tt>image:</tt>
+
<source lang="bash">
*:<tt>registry</tt> - the registry from which Kubernetes will pull images (<tt>pureengage-docker-staging.jfrog.io</tt> by default)
+
job:
*:<tt>tag</tt> - the container image version
+
  storage:
*<tt>imagePullSecrets:</tt>
+
    gspPrefix: <prefix> # The URI path prefix under which GSP savepoints, checkpoints, and high availability data will be stored
*:<tt>jfrog-stage-credentials</tt> - the secret from which Kubernetes will get credentials to pull the image from the registry
+
    gcaSnapshots: <path> # The URI path under which GCA snapshots will be stored
*<tt>kafka:</tt>
+
</source>
*:<tt>bootstrap</tt> - the Kafka address to align with the infrastructure Kafka
+
 
*<tt>storage:</tt>
+
To enable other types of S3-compatible storage, modify the following entries in the '''values.yaml''' file:
*:<tt>gspPrefix</tt> - the s3 bucket name
 
*<tt>s3</tt> - the applicable s3 details defined with the OBC (see {{Link-SomewhereInThisVersion|manual=GIMPEGuide|topic=ConfigureGSP|anchor=S3Data|display text=Get S3 data}})
 
{{AnchorDiv|YAML-file}}
 
====The GSP '''values.yaml''' file====
 
The following sample GSP '''values.yaml''' file, which may not be completely up to date, shows the key parameter values you must override.
 
  
<source lang="bash">global:
+
<source lang="bash">
  rbac:
 
    create: true
 
  serviceAccount:
 
    create: true
 
image:
 
  registry: pureengage-docker-staging.jfrog.io
 
  repository: gim/gsp
 
  pullPolicy: IfNotPresent
 
  tag: <image-version>
 
imagePullSecrets:
 
  pureengage-docker-dev: {}
 
  pureengage-docker-staging: {}
 
  jfrog-stage-credentials: {}
 
 
azure:
 
azure:
 
   enabled: false
 
   enabled: false
environment: dev
 
location: eastus2
 
 
job:
 
job:
   rbac:
+
   storage:
     create: null
+
     gspPrefix: <bucket-name> # The bucket where GSP savepoints, checkpoints, and high-availability data will be stored
  serviceAccount:
+
     gcaSnapshots: <bucket-name> # The bucket where the GCA snapshots will be stored.
     create: true
+
     s3: <s3-details> # The applicable details defined for the OBC or GCP bucket.
    name: gsp
+
</source>
  id: '00000000000000000000000000000000'
+
'''Note:''' The <code>host</code> parameter is ignored.
  className: com.genesyslab.gim.fsp.App
+
 
  savepoint: ''
+
====GKE example====
  checkpointing:
+
<source lang="bash">azure:
     mode: AT_LEAST_ONCE
+
   enabled: false
    interval: 20 min
+
...
    timeout: 40 min
+
job:
    minPause: 15 min
 
    unaligned: 'false'
 
    concurrent: '1'
 
    external: ''
 
    tolerableFailed: '300'
 
  parallelism: '2'
 
  autoCreateTopics:
 
    partitions: 1
 
    replicationFactor: 3
 
   dumps: /var/lib/dumps
 
  timeDeviation: PT15S
 
  idleness: PT15M
 
  objectReuse: 'true'
 
  kafkaRateLimit: null
 
 
   storage:
 
   storage:
 
     host: gspstate{{.Values.short_location}}{{.Values.environment}}.blob.core.windows.net
 
     host: gspstate{{.Values.short_location}}{{.Values.environment}}.blob.core.windows.net
 
     #gspPrefix: wasbs://gsp-state@{{ tpl .Values.job.storage.host . }}/{{ .Release.Name }}/
 
     #gspPrefix: wasbs://gsp-state@{{ tpl .Values.job.storage.host . }}/{{ .Release.Name }}/
     gspPrefix: "s3p://<bucket-name>/{{ .Release.Name }}/"
+
     gspPrefix: "s3p://test-example-bucket-one/{{ .Release.Name }}/"                                                                              
 
     #gcaSnapshots: wasbs://gca@{{ tpl .Values.job.storage.host . }}/
 
     #gcaSnapshots: wasbs://gca@{{ tpl .Values.job.storage.host . }}/
     gcaSnapshots: "s3p://<bucket-name>/gca/"
+
     gcaSnapshots: "s3p://test-example-bucket-one/gca/"                                                                
 
     checkpoints: '{{ tpl .Values.job.storage.gspPrefix . }}checkpoints'
 
     checkpoints: '{{ tpl .Values.job.storage.gspPrefix . }}checkpoints'
 
     savepoints: '{{ tpl .Values.job.storage.gspPrefix . }}savepoints'
 
     savepoints: '{{ tpl .Values.job.storage.gspPrefix . }}savepoints'
 
     highAvailability: '{{ tpl .Values.job.storage.gspPrefix . }}ha'
 
     highAvailability: '{{ tpl .Values.job.storage.gspPrefix . }}ha'
 
     s3:
 
     s3:
       endpoint: "https://<bucket-host>:<bucket-port>"
+
       endpoint: "https://storage.googleapis.com:443"
       accessKey: "<access-key-value>"
+
       accessKey: "<access Key>"
       secretKey: "<secret-key-value>"
+
       secretKey: "<secret key>"
 
       pathStyleAccess: "true"
 
       pathStyleAccess: "true"
#    pvc:
+
</source>
#      create: true
 
#      mountPath: /opt/flink/state
 
#      claim: ''
 
#      claimSize: 10Gi
 
#      storageClass: standard
 
  log:
 
    level: INFO
 
    loggers:
 
      org.apache.kafka: INFO
 
  highAvailability:
 
    high-availability: org.apache.flink.kubernetes.highavailability.KubernetesHaServicesFactory
 
    high-availability.jobmanager.port: '50010'
 
    kubernetes.namespace: '{{ .Release.Namespace }}'
 
    kubernetes.cluster-id: '{{ .Release.Name }}'
 
monitoring:
 
  enabled: true
 
  port: 9249
 
  dashboards:
 
    targetDirectory: /var/lib/grafana/dashboards/{{ .Release.Namespace }}
 
tm:
 
  nameOverride: ''
 
  fullnameOverride: ''
 
  numberOfTaskSlots: '2'
 
  deployment:
 
    replicaCount: 1
 
  port:
 
    rpc: 6122
 
  memory:
 
    jvmOverheadFraction: 0.18
 
    jvmOverheadMin: 220mb
 
    jvmOverheadMax: ''
 
    jvmMetaspace: 256mb
 
    offHeap: 128mb
 
    managed: ''
 
    heap: ''
 
    networkMax: ''
 
  resources:
 
    requests:
 
      memory: 1Gi
 
      cpu: '0.05'
 
    limits:
 
      memory: 3Gi
 
      cpu: '2'
 
  tolerations: []
 
  affinity: {}
 
jm:
 
  nameOverride: ''
 
  fullnameOverride: ''
 
  savepoints: ''
 
  port:
 
    rpc: 6123
 
    blob: 6124
 
    rest: 8081
 
  resources:
 
    requests:
 
      memory: 1Gi
 
      cpu: '0.05'
 
    limits:
 
      memory: 2048Mi
 
      cpu: '1'
 
monitor:
 
  rbac:
 
    create: null
 
  serviceAccount:
 
    create: true
 
    annotations: {}
 
    name: '{{ .Release.Name }}-monitor'
 
podSecurityContext: {}
 
securityContext: {}
 
service:
 
  type: ClusterIP
 
  port: 80
 
ingress:
 
  enabled: false
 
  annotations: {}
 
  hosts: []
 
  tls: []
 
kafka:
 
  bootstrap: 'infra-kafka-cp-kafka.infra.svc.cluster.local:9092'
 
  groupId: null
 
  clientId: gim-gsp
 
  offsets: GROUP_OFFSETS
 
  topic:
 
    out:
 
      interactions: gsp-ixn
 
      agentStates: gsp-sm
 
      outbound: gsp-outbound
 
      custom: gsp-custom
 
      cfg: gsp-cfg
 
    in:
 
      digitalItx: digital-itx
 
      digitalAgentStates: digital-agentstate
 
  maxRequestSize: '4194304'
 
  compressionType: lz4
 
  maxBlockMs: '322000'
 
  metadataMaxAgeMs: 600000
 
  metadataMaxIdleMs: 600000
 
  requestTimeoutMs: 32000
 
schemaRegistry:
 
  enabled: false
 
  url: ''
 
  user: ''
 
  password: ''
 
dnsConfig:
 
  options:
 
  - name: ndots
 
    value: '3'</source>
 
 
|Status=No
 
|Status=No
 
}}{{Section
 
}}{{Section
|sectionHeading=Configure Kubernetes
+
|sectionHeading=Kubernetes API
 +
|anchor=GSP_KubernetesPermissions
 
|alignment=Vertical
 
|alignment=Vertical
|structuredtext={{Notices|Notice=PEComingSoon}}
+
|structuredtext=GSP uses Apache Flink for stateful stream processing, with communications handled via the Kubernetes API. To use the Kubernetes API, GSP must have the permissions shown in the following example:
 +
{{{!}} class="wikitable"
 +
{{!}}+
 +
!Verbs
 +
!On Resource
 +
!API Group
 +
!Comment
 +
{{!}}-
 +
{{!}}get
 +
list
 +
 
 +
watch
 +
 
 +
delete
 +
{{!}}jobs
 +
{{!}}batch
 +
{{!}}GSP uses these commands during upgrade and for a pre-upgrade hook to ensure that the previous version of GSP is stopped before upgrading to the new version.
 +
{{!}}-
 +
{{!}}create
 +
update
 +
 
 +
patch
 +
 
 +
get
 +
 
 +
list
 +
 
 +
watch
 +
 
 +
delete
 +
{{!}}configmap
 +
{{!}}general ("")
 +
{{!}}GSP uses these commands to:
 +
 
 +
*Support Flink's Kubernetes high availability (HA) services
 +
*Record the path to the savepoint (periodically taken by the '''take-savepoint''' cron job and by the upgrade hook)
 +
{{!}}}
 +
 
 +
{{AnchorDiv|GSP_Config_ArbitraryUIDs}}
 
|Status=No
 
|Status=No
 
}}{{Section
 
}}{{Section
|sectionHeading=Configure security
+
|sectionHeading=Configure GSP behavior
|anchor=Security
+
|anchor=Options
 
|alignment=Vertical
 
|alignment=Vertical
|structuredtext=The security context settings define the privilege and access control settings for pods and containers.
+
|structuredtext=You can specify values in the '''values.yaml''' file to override the default values of configuration options that control GSP behavior and to customize user data and Outbound field mappings.
  
By default, the user and group IDs are set in the GSP '''values.yaml''' file as <tt>500:500:500</tt>, meaning the '''genesys''' user.
+
You can override aspects of the default configuration to modify GSP behavior and customize the way data is stored in the Info Mart database.
 +
 
 +
You can customize the following:
 +
 
 +
*[[{{FULLPAGENAME}}#ConfigOptions|Configuration options]], to modify data-related aspects of GSP behavior
 +
*[[{{FULLPAGENAME}}#UserData|User data mappings]], to map custom key-value pairs (KVPs), which are attached to event and reporting protocol data, to tables and columns in the Info Mart database
 +
*[[{{FULLPAGENAME}}#Outbound|Outbound record field mappings]], to map custom CX Contact record field data to Outbound-related tables and columns in the Info Mart database
 +
 
 +
{{AnchorDiv|ConfigOptions}}
 +
===Customize configuration option settings===
 +
For full information about the options you can configure, including the default and valid values, see {{Link-SomewhereInThisVersion|manual=GIMPEGuide|topic=GSPConfigOptions}}.
 +
 
 +
To configure options, edit the GSP '''values.yaml''' file. Under the '''cfgOptions''' object, specify the option and value in JSON format, noting the following:
 +
 
 +
*Options are separately configurable by tenant and, where applicable, by media type or even at the level of individual queues (DNs or scripts).
 +
*Where an option can be configured at various levels, you can override a value set at a higher level (for example, for a particular media type in general) to set a different value for a particular lower-level object (for example, for that media type for an individual DN).
 +
*See the {{Link-SomewhereInThisVersion|manual=GIMPEGuide|topic=GSPConfigOptions|anchor=ConfigLevel|display text=note about configuration levels}} for information about the available configuration levels for certain options.
 +
 
 +
The entries in the '''values.yaml''' file are structured as follows:
 
<source lang="bash">
 
<source lang="bash">
securityContext:
+
cfgOptions:
  runAsNonRoot: true
+
    "<tenant_id>": |
  runAsUser: 500
+
      standard:
  runAsGroup: 500
+
        <option 1>: <value>
  fsGroup: 500
+
      media:
 +
        <media type 1>:
 +
          <option 2>: <value 1>
 +
          <option 3>: <value 1>
 +
        <media type 2>:
 +
          <option 2>: <value 2>
 +
          <option 4>: <value 1>
 +
      dn:
 +
        <dn_id>:
 +
          media:
 +
            <media type 1>:
 +
              <option 2>: <value 3>
 +
      script:
 +
        <script_id>:
 +
          media:
 +
            <media type 2>:
 +
              <option 2>: <value 4>
 +
      ...
 +
</source>
 +
 
 +
For an example, see [[{{FULLPAGENAME}}#Example|example]].
 +
 
 +
<!-- GIM-14206-->
 +
{{AnchorDiv|UserData}}
 +
===Customize user data mapping===
 +
Genesys Info Mart uses a wide range of user-data KVPs from a number of upstream services to populate data in the Info Mart database. For full information about user data in Genesys Info Mart, see {{Link-SomewhereInThisVersion|manual=GIMPEGuide|topic=UserData}}.
  
containerSecurityContext: {}
+
As described on [link TBD], you can extend storage of user data in the Info Mart database to include additional user-data KVPs you want to capture as custom user-data facts or dimensions.
 +
 
 +
To configure user-data mapping, edit the GSP '''values.yaml''' file. Under the '''udeMapping''' object , specify the mapping between your custom KVPs and the custom user-data database table(s) and column(s), noting the following:
 +
 
 +
*The mapping, which is specified in JSON format, is configured separately by tenant.
 +
*In addition to specifying the database table and column in which to store the KVP value, you also specify the ''propagation rule'' that Genesys Info Mart uses to determine what value to store if more than one value is extracted for the same key in the same interaction. See {{Link-SomewhereInThisVersion|manual=GIMPEGuide|topic=UserData|anchor=PropagationRules|display text=Propagation rules}} for more information.
 +
*You can specify a default value to use if the KVP value is null. You must provide a default value for dimensions.
 +
*You map custom user-data dimensions via the IRF_USER_DATA_KEYS table, where you specify the foreign key reference(s) for the user-data dimension table(s).
 +
 
 +
Genesys Info Mart provides the following sample tables in the Info Mart database schema for storage of custom KVPs:
 +
 
 +
*USER_DATA_CUST_DIM_1 — for low-cardinality user data to be stored as dimensions
 +
*IRF_USER_DATA_CUST_1 — for high-cardinality user data to be stored as facts
 +
 
 +
The structure of the entries to specify in the '''values.yaml''' file is:
 +
 
 +
<!-- Writer -- some questions we should try and answer at some point:
 +
1. Can you customize the table names (USER_DATA_CUST_DIM_1, IRF_USER_DATA_CUST_1) and column names (DIM_ATTRIBUTE_1, CUSTOM_DATA_1, etc.; also CUSTOM_KEY_1 in IRF_USER_DATA_KEYS)? i.e., Is it OK to show these as <variables>?
 +
2 '''Alexey,''' the example [[{{FULLPAGENAME}}#Example|at the bottom of the page]] is taken from an example you sent me. Why are these particular IRF_USER_DATA_GEN_1 entries listed? In GIM Classic, we say these particular mappings are predefined by default. Do they need to be overtly specified here, or should we change the example to show non-standard KVPs?
 +
-->
 +
 
 +
<source lang="bash">
 +
udeMapping:
 +
  "<tenant_id">: |
 +
    IRF_USER_DATA_KEYS:
 +
      columns:
 +
        <CUSTOM_KEY_1>:
 +
          type: dim
 +
          table: <USER_DATA_CUST_DIM_1>
 +
          attributes:
 +
            <DIM_ATTRIBUTE_1>:
 +
              kvp: <KVP>
 +
              rule: <propagation_rule>
 +
              default: <default_value>
 +
            ...
 +
    <IRF_USER_DATA_CUST_1>:
 +
      columns:
 +
        <CUSTOM_DATA_1>:
 +
          type: value
 +
          kvp: <KVP>
 +
          rule: <propagation_rule>
 +
          default: <default_value>
 +
        ...
 +
</source>
 +
 
 +
See the [[{{FULLPAGENAME}}#Example|example]].
 +
 
 +
{{AnchorDiv|Outbound}}
 +
===Customize Outbound field mapping===
 +
<!--Writer: In GIM Classic, we've been religious about using the phrase "Outbound Contact" to refer to OCS data. For PE and Multicloud in general, we should use just "Outbound". And for PE, only CX Contact applies.-->
 +
 
 +
Genesys Info Mart stores data about every outbound contact attempt, based on Record Field data it receives from the CX Contact (CXC) service. As described on {{Link-SomewhereInThisVersion|manual=GIMPEGuide|topic=Outbound}}, some of the mapping between Field data and the Info Mart database tables and columns is predefined, and some is custom.
 +
 
 +
To customize outbound mapping, edit the GSP values.yaml file.  Under the '''ocsMapping''' object, specify the mapping between your custom record fields and the tables and columns provided in the Info Mart database for custom record field data, namely:
 +
 
 +
*In the CONTACT_ATTEMPT_FACT table:
 +
**10 floating-point numbers: <tt>numeric(14,4)</tt>
 +
**20 integers: <tt>integer</tt>
 +
**30 strings: <tt>varchar(255)</tt>
 +
*In the RECORD_FIELD_GROUP_1 and RECORD_FIELD_GROUP_2 tables:
 +
**10 strings each: <tt>varchar(255)</tt>
 +
 
 +
<!--Writer: Placeholder for something to say about rpcValue and conversionValue (see question 2).-->
 +
<!--Writer: More questions we should pursue:
 +
1Per the CXC documentation ({{Link-AnywhereElse|product=PEC-OU|version=Current|manual=CXContact|topic=FieldLabels}}), by default "all user-defined fields in a contact list are labelled as Other1, Other2, Other3, and so on." In the following example, should I change all instances of "GenRecordField" to "Other"? -- e.g., CAF.RECORD_FIELD_1 populated by field: Other1, RECORD_FIELD_GROUP_1.RECORD_FIELD_1_STRING_1 populated by field: Other1String1, etc.
 +
2 I cannot find any reference to OCS-equivalent right_person and conversion configuration in the CXC documentation. Are rpcValue and conversionValue applicable for PE?
 +
-->
 +
The mapping, which is specified in JSON format, is configured separately by tenant. The structure of the entries is:
 +
 
 +
<source lang="bash">
 +
ocsMapping:
 +
  "<tenant_id>": |
 +
    CONTACT_ATTEMPT_FACT:
 +
      columns:
 +
        RECORD_FIELD_1:
 +
          field: <numericFieldName>
 +
          rpcValue:
 +
          conversionValue:
 +
        ...
 +
        RECORD_FIELD_11:
 +
          field: <intFieldName>
 +
          rpcValue:
 +
          conversionValue:
 +
        ...
 +
        RECORD_FIELD_31:
 +
          field: <stringFieldName>
 +
          rpcValue:
 +
          conversionValue:
 +
        ...
 +
    RECORD_FIELD_GROUP_1:
 +
      columns:
 +
        RECORD_FIELD_1_STRING_1:
 +
          field: <stringFieldName>
 +
          rpcValue:
 +
          conversionValue:
 +
        ...
 +
    RECORD_FIELD_GROUP_2:
 +
      columns:
 +
        RECORD_FIELD_2_STRING_1:
 +
          field: <stringFieldName>
 +
          rpcValue:
 +
          conversionValue:
 +
        ...
 
</source>
 
</source>
===Arbitrary UIDs in OpenShift===
 
If you want to use arbitrary UIDs in your OpenShift deployment, you must override the '''securityContext''' settings in the GSP '''values.yaml''' file, so that you do not define any specific IDs.
 
  
 +
See the [[{{FULLPAGENAME}}#Example|example]].
 +
 +
{{AnchorDiv|OptionsExample}}
 +
===Example===
 
<source lang="bash">
 
<source lang="bash">
securityContext:
+
cfgOptions:
   runAsNonRoot: true
+
    "eb0c9f3a-5dca-498f-98d5-7610f5fd1015": |
  runAsUser: null
+
      standard:
  runAsGroup: 0
+
        completed-queues: iWD_Completed,iWD_Processed_ext
  fsGroup: null
+
        populate-workbin-as-hold: false
 +
      media:
 +
        voice:
 +
          q-answer-threshold: 30
 +
      media:
 +
        email:
 +
          q-short-abandoned-threshold: 20
 +
      dn:
 +
        eb0c9f3a-5dca-498f-98d5-7610f5fd1015_MM_VQ:
 +
          media:
 +
            email:
 +
              q-answer-threshold: 90
 +
              q-short-abandoned-threshold: 40
 +
      script:
 +
        eb0c9f3a-5dca-498f-98d5-7610f5fd1015_ixn_queue:
 +
          media:
 +
            chat:
 +
              q-answer-threshold: 20
 +
      script:
 +
        eb0c9f3a-5dca-498f-98d5-7610f5fd1015_dev.IQ:
 +
          standard:
 +
            populate-ixnqueue-facts: false
 +
 
 +
udeMapping:
 +
   "eb0c9f3a-5dca-498f-98d5-7610f5fd1015": |
 +
    IRF_USER_DATA_KEYS:
 +
      columns:
 +
        CUSTOM_KEY_1:
 +
          type: dim
 +
          table: USER_DATA_CUST_DIM_1
 +
          attributes:
 +
            DIM_ATTRIBUTE_1:
 +
              kvp: BusinessLine
 +
              rule: CALL
 +
              default: retail
 +
            DIM_ATTRIBUTE_2:
 +
              kvp: RULE_PARTY
 +
              rule: PARTY
 +
              default: none
 +
            DIM_ATTRIBUTE_3:
 +
              kvp: RULE_IRF
 +
              rule: IRF
 +
              default: none
 +
            DIM_ATTRIBUTE_4:
 +
              kvp: RULE_IRF_INITIAL
 +
              rule: IRF_INITIAL
 +
              default: none
 +
            DIM_ATTRIBUTE_5:
 +
              kvp: RULE_IRF_FIRST_UPDATE
 +
              rule: IRF_FIRST_UPDATE
 +
              default: none
 +
    IRF_USER_DATA_CUST_1:
 +
      columns:
 +
        CUSTOM_DATA_1:
 +
          type: value
 +
          kvp: RULE_CALL
 +
          rule: CALL
 +
          default: none
 +
        CUSTOM_DATA_2:
 +
          type: value
 +
          kvp: RULE_PARTY
 +
          rule: PARTY
 +
          default: none
 +
        CUSTOM_DATA_3:
 +
          type: value
 +
          kvp: RULE_IRF
 +
          rule: IRF
 +
        CUSTOM_DATA_4:
 +
          type: value
 +
          kvp: RULE_IRF_FIRST_UPDATE
 +
          rule: IRF_FIRST_UPDATE
 +
        CUSTOM_DATA_5:
 +
          type: value
 +
          kvp: RULE_IRF_INITIAL
 +
          rule: IRF_INITIAL
 +
        CUSTOM_DATA_6:
 +
          type: value
 +
          kvp: RULE_IRF_ROUTE
 +
          rule: IRF_ROUTE
 +
    IRF_USER_DATA_GEN_1:
 +
      columns:
 +
        CASE_ID:
 +
          type: value
 +
          kvp: CaseID
 +
          rule: Call
 +
          default: none
 +
        CUSTOMER_ID:
 +
          type: value
 +
          kvp: GIM_GRP
 +
          rule: Call
 +
          default: none
  
containerSecurityContext: {}
+
ocsMapping:
 +
  "eb0c9f3a-5dca-498f-98d5-7610f5fd1015": |
 +
    CONTACT_ATTEMPT_FACT:
 +
      columns:
 +
        RECORD_FIELD_1:
 +
          field: GenRecordField1
 +
          rpcValue:
 +
          conversionValue:
 +
        RECORD_FIELD_2:
 +
          field: GenRecordField2
 +
          rpcValue:
 +
          conversionValue:
 +
        ...
 +
        RECORD_FIELD_60:
 +
          field: GenRecordField60
 +
          rpcValue:
 +
          conversionValue:
 +
    RECORD_FIELD_GROUP_1:
 +
      columns:
 +
        RECORD_FIELD_1_STRING_1:
 +
          field: GenRecordField1String1
 +
          rpcValue:
 +
          conversionValue:
 +
        RECORD_FIELD_1_STRING_2:
 +
          field: GenRecordField1String2
 +
          rpcValue:
 +
          conversionValue:
 +
        RECORD_FIELD_1_STRING_3:
 +
        ...
 +
    RECORD_FIELD_GROUP_2:
 +
      columns:
 +
        RECORD_FIELD_2_STRING_1:
 +
          field: GenRecordField2String1
 +
          rpcValue:
 +
          conversionValue:
 +
        RECORD_FIELD_2_STRING_2:
 +
        ...
 
</source>
 
</source>
 
|Status=No
 
|Status=No

Latest revision as of 13:31, March 10, 2023

This topic is part of the manual Genesys Info Mart Private Edition Guide for version Current of Reporting.

Learn how to configure GIM Stream Processor (GSP).

GSP Helm chart overrides

The GSP requires some configuration for deployment that must be made by modifying the GSP's default Helm chart. You do this by creating override entries in the GSP's values.yaml file.

Download the GSP Helm charts from your image registry, using the appropriate credentials.

For information about how to download the Helm charts, see Downloading your Genesys Multicloud CX containers. To find the correct Helm chart version for your release, see Helm charts and containers for Genesys Info Mart for the Helm chart version you must download for your release. For general information about Helm chart overrides, see Overriding Helm chart values in the Genesys Multicloud CX Private Edition Guide.

At minimum, you must create entries in the values.yaml file to specify key system information, as described in the following sections.

Important
Treat your modified values.yaml file as source code, which you are responsible to maintain so that your overrides are preserved and available for reuse when you upgrade.

Image registry and pull secret

Image registry

Create an entry in the GSP's values.yaml file to specify the location of your image registry. This is the repository from which Kubernetes pulls images.

The location of the image registry is defined when you set up the environment for the GSP. It is represented in the system as the docker-registry. In the GSP Helm chart, the repository is represented as image: registry, as shown in the following example. You can optionally set a container version for the image, as in the following example.

image: # The repository from which Kubernetes pulls images
  registry: <your_container_registry>  # The default registry is pureengage-docker-staging.jfrog.io
  tag: <image_tag> # The container image tag/version

Pull secret

When you set up your environment, you define a pull secret for the image registry (docker-registry). You must include the pull secret in the GSP's values.yaml file in order for Kubernetes to be able to pull from the repository.

imagePullSecrets:
  docker-registry: {<pull-secret>} # The credentials Kubernetes will use to pull the image from the registry

Note that other services use a different syntax than this to configure the repository pull secret, as follows:

imagePullSecrets:
  name: docker-registry

Genesys Info Mart, GIM Stream Processor, and GIM Configuration Adaptor helm charts all support advanced templating that allow the helm to create the pull secret automatically; hence the variation in syntax.

Kafka


Kafka secret

If Kafka is configured with authentication, you must configure the Kafka secret so GSP can access Kafka. The Kafka secret is provisioned in the system as kafka-secrets when you set up the environment for GSP. Configure the Kafka secret by creating a Helm chart override in the values.yaml file.

kafka:
  password: <kafka-password> # Credentials for accessing Kafka. This secret is created during deployment.

Kafka bootstrap

To allow the Kafka service on GSP to align with the infrastructure Kafka service, make a Helm override entry with the location of the Kafka bootstrap.

kafka:
  bootstrap: <kafka-bootstrap-location> # The Kafka address to align with the infrastructure Kafka

Custom Kafka topic names

Some of the Kafka topics used by the GSP support customizing the topic name. If any topic name has been customized, ensure it is represented as a Helm chart override entry, using the kafka:topic parameter.

For a list of the Kafka topics that GSP produces and consumes, including which of those support customized naming, see Before you begin GSP deployment.

S3-compatible storage

S3 storage credentials

When you set up the environment for GSP, you provision S3-compatible object storage for GSP to use as a persistent data store. In the values.yaml file, record the credentials needed by GSP to access this storage.

gsp-s3: <s3-credentials> # Credentials for accessing S3-compatible storage

Enable S3-compatible storage

When you set up your environment for the GSP, you provision S3-compatible object storage for the GSP's persistent data store. You must enable this storage with override entries in the values.yaml file.

By default, GSP is configured to use Azure Blob Storage as the persistent data store. If you have provisioned Azure Blob Storage in your deployment, modify the following entries in the values.yaml file:

job:
  storage:
    gspPrefix: <prefix> # The URI path prefix under which GSP savepoints, checkpoints, and high availability data will be stored
    gcaSnapshots: <path> # The URI path under which GCA snapshots will be stored

To enable other types of S3-compatible storage, modify the following entries in the values.yaml file:

azure:
  enabled: false
job:
  storage:
    gspPrefix: <bucket-name> # The bucket where GSP savepoints, checkpoints, and high-availability data will be stored
    gcaSnapshots: <bucket-name> # The bucket where the GCA snapshots will be stored.
    s3: <s3-details> # The applicable details defined for the OBC or GCP bucket.

Note: The host parameter is ignored.

GKE example

azure:
  enabled: false
...
job:
  storage:
    host: gspstate{{.Values.short_location}}{{.Values.environment}}.blob.core.windows.net
    #gspPrefix: wasbs://gsp-state@{{ tpl .Values.job.storage.host . }}/{{ .Release.Name }}/
    gspPrefix: "s3p://test-example-bucket-one/{{ .Release.Name }}/"                                                                               
    #gcaSnapshots: wasbs://gca@{{ tpl .Values.job.storage.host . }}/
    gcaSnapshots: "s3p://test-example-bucket-one/gca/"                                                                  
    checkpoints: '{{ tpl .Values.job.storage.gspPrefix . }}checkpoints'
    savepoints: '{{ tpl .Values.job.storage.gspPrefix . }}savepoints'
    highAvailability: '{{ tpl .Values.job.storage.gspPrefix . }}ha'
    s3:
      endpoint: "https://storage.googleapis.com:443"
      accessKey: "<access Key>"
      secretKey: "<secret key>"
      pathStyleAccess: "true"

Kubernetes API

GSP uses Apache Flink for stateful stream processing, with communications handled via the Kubernetes API. To use the Kubernetes API, GSP must have the permissions shown in the following example:

Verbs On Resource API Group Comment
get

list

watch

delete

jobs batch GSP uses these commands during upgrade and for a pre-upgrade hook to ensure that the previous version of GSP is stopped before upgrading to the new version.
create

update

patch

get

list

watch

delete

configmap general ("") GSP uses these commands to:
  • Support Flink's Kubernetes high availability (HA) services
  • Record the path to the savepoint (periodically taken by the take-savepoint cron job and by the upgrade hook)

Configure GSP behavior

You can specify values in the values.yaml file to override the default values of configuration options that control GSP behavior and to customize user data and Outbound field mappings.

You can override aspects of the default configuration to modify GSP behavior and customize the way data is stored in the Info Mart database.

You can customize the following:

  • Configuration options, to modify data-related aspects of GSP behavior
  • User data mappings, to map custom key-value pairs (KVPs), which are attached to event and reporting protocol data, to tables and columns in the Info Mart database
  • Outbound record field mappings, to map custom CX Contact record field data to Outbound-related tables and columns in the Info Mart database

Customize configuration option settings

For full information about the options you can configure, including the default and valid values, see GSP configuration options.

To configure options, edit the GSP values.yaml file. Under the cfgOptions object, specify the option and value in JSON format, noting the following:

  • Options are separately configurable by tenant and, where applicable, by media type or even at the level of individual queues (DNs or scripts).
  • Where an option can be configured at various levels, you can override a value set at a higher level (for example, for a particular media type in general) to set a different value for a particular lower-level object (for example, for that media type for an individual DN).
  • See the note about configuration levels for information about the available configuration levels for certain options.

The entries in the values.yaml file are structured as follows:

cfgOptions:
    "<tenant_id>": |
      standard:
        <option 1>: <value>
      media:
        <media type 1>:
          <option 2>: <value 1>
          <option 3>: <value 1>
        <media type 2>:
          <option 2>: <value 2>
          <option 4>: <value 1>
      dn:
        <dn_id>:
          media:
            <media type 1>:
              <option 2>: <value 3>
      script:
        <script_id>:
          media:
            <media type 2>:
              <option 2>: <value 4> 
      ...

For an example, see example.

Customize user data mapping

Genesys Info Mart uses a wide range of user-data KVPs from a number of upstream services to populate data in the Info Mart database. For full information about user data in Genesys Info Mart, see [[PEC-REP/Current/GIMPEGuide/UserData|]].

As described on [link TBD], you can extend storage of user data in the Info Mart database to include additional user-data KVPs you want to capture as custom user-data facts or dimensions.

To configure user-data mapping, edit the GSP values.yaml file. Under the udeMapping object , specify the mapping between your custom KVPs and the custom user-data database table(s) and column(s), noting the following:

  • The mapping, which is specified in JSON format, is configured separately by tenant.
  • In addition to specifying the database table and column in which to store the KVP value, you also specify the propagation rule that Genesys Info Mart uses to determine what value to store if more than one value is extracted for the same key in the same interaction. See Propagation rules for more information.
  • You can specify a default value to use if the KVP value is null. You must provide a default value for dimensions.
  • You map custom user-data dimensions via the IRF_USER_DATA_KEYS table, where you specify the foreign key reference(s) for the user-data dimension table(s).

Genesys Info Mart provides the following sample tables in the Info Mart database schema for storage of custom KVPs:

  • USER_DATA_CUST_DIM_1 — for low-cardinality user data to be stored as dimensions
  • IRF_USER_DATA_CUST_1 — for high-cardinality user data to be stored as facts

The structure of the entries to specify in the values.yaml file is:


udeMapping:
  "<tenant_id">: |
    IRF_USER_DATA_KEYS:
      columns:
        <CUSTOM_KEY_1>:
          type: dim
          table: <USER_DATA_CUST_DIM_1>
          attributes:
            <DIM_ATTRIBUTE_1>:
              kvp: <KVP>
              rule: <propagation_rule>
              default: <default_value>
            ...
    <IRF_USER_DATA_CUST_1>:
      columns:
        <CUSTOM_DATA_1>:
          type: value
          kvp: <KVP>
          rule: <propagation_rule>
          default: <default_value>
        ...

See the example.

Customize Outbound field mapping

Genesys Info Mart stores data about every outbound contact attempt, based on Record Field data it receives from the CX Contact (CXC) service. As described on [[PEC-REP/Current/GIMPEGuide/Outbound|]], some of the mapping between Field data and the Info Mart database tables and columns is predefined, and some is custom.

To customize outbound mapping, edit the GSP values.yaml file. Under the ocsMapping object, specify the mapping between your custom record fields and the tables and columns provided in the Info Mart database for custom record field data, namely:

  • In the CONTACT_ATTEMPT_FACT table:
    • 10 floating-point numbers: numeric(14,4)
    • 20 integers: integer
    • 30 strings: varchar(255)
  • In the RECORD_FIELD_GROUP_1 and RECORD_FIELD_GROUP_2 tables:
    • 10 strings each: varchar(255)

The mapping, which is specified in JSON format, is configured separately by tenant. The structure of the entries is:

ocsMapping:
  "<tenant_id>": |
    CONTACT_ATTEMPT_FACT:
      columns:
        RECORD_FIELD_1:
          field: <numericFieldName>
          rpcValue:
          conversionValue:
        ...
        RECORD_FIELD_11:
          field: <intFieldName>
          rpcValue:
          conversionValue:
        ...
        RECORD_FIELD_31:
          field: <stringFieldName>
          rpcValue:
          conversionValue:
        ...
    RECORD_FIELD_GROUP_1:
      columns:
        RECORD_FIELD_1_STRING_1:
          field: <stringFieldName>
          rpcValue:
          conversionValue:
        ...
    RECORD_FIELD_GROUP_2:
      columns:
        RECORD_FIELD_2_STRING_1:
          field: <stringFieldName>
          rpcValue:
          conversionValue:
        ...

See the example.

Example

cfgOptions:
    "eb0c9f3a-5dca-498f-98d5-7610f5fd1015": |
      standard:
        completed-queues: iWD_Completed,iWD_Processed_ext
        populate-workbin-as-hold: false
      media:
        voice:
          q-answer-threshold: 30
      media:
        email:
          q-short-abandoned-threshold: 20
      dn:
        eb0c9f3a-5dca-498f-98d5-7610f5fd1015_MM_VQ:
          media:
            email:
              q-answer-threshold: 90
              q-short-abandoned-threshold: 40
      script:
        eb0c9f3a-5dca-498f-98d5-7610f5fd1015_ixn_queue:
          media:
            chat:
              q-answer-threshold: 20
      script:
        eb0c9f3a-5dca-498f-98d5-7610f5fd1015_dev.IQ:
          standard:
            populate-ixnqueue-facts: false

udeMapping:
  "eb0c9f3a-5dca-498f-98d5-7610f5fd1015": |
    IRF_USER_DATA_KEYS:
      columns:
        CUSTOM_KEY_1:
          type: dim
          table: USER_DATA_CUST_DIM_1
          attributes:
            DIM_ATTRIBUTE_1:
              kvp: BusinessLine
              rule: CALL
              default: retail
            DIM_ATTRIBUTE_2:
              kvp: RULE_PARTY
              rule: PARTY
              default: none
            DIM_ATTRIBUTE_3:
              kvp: RULE_IRF
              rule: IRF
              default: none
            DIM_ATTRIBUTE_4:
              kvp: RULE_IRF_INITIAL
              rule: IRF_INITIAL
              default: none
            DIM_ATTRIBUTE_5:
              kvp: RULE_IRF_FIRST_UPDATE
              rule: IRF_FIRST_UPDATE
              default: none
    IRF_USER_DATA_CUST_1:
      columns:
        CUSTOM_DATA_1:
          type: value
          kvp: RULE_CALL
          rule: CALL
          default: none
        CUSTOM_DATA_2:
          type: value
          kvp: RULE_PARTY
          rule: PARTY
          default: none
        CUSTOM_DATA_3:
          type: value
          kvp: RULE_IRF
          rule: IRF
        CUSTOM_DATA_4:
          type: value
          kvp: RULE_IRF_FIRST_UPDATE
          rule: IRF_FIRST_UPDATE
        CUSTOM_DATA_5:
          type: value
          kvp: RULE_IRF_INITIAL
          rule: IRF_INITIAL
        CUSTOM_DATA_6:
          type: value
          kvp: RULE_IRF_ROUTE
          rule: IRF_ROUTE
    IRF_USER_DATA_GEN_1:
      columns:
        CASE_ID:
          type: value
          kvp: CaseID
          rule: Call
          default: none
        CUSTOMER_ID:
          type: value
          kvp: GIM_GRP
          rule: Call
          default: none

ocsMapping:
  "eb0c9f3a-5dca-498f-98d5-7610f5fd1015": |
    CONTACT_ATTEMPT_FACT:
      columns:
        RECORD_FIELD_1:
          field: GenRecordField1
          rpcValue:
          conversionValue:
        RECORD_FIELD_2:
          field: GenRecordField2
          rpcValue:
          conversionValue:
        ...
        RECORD_FIELD_60:
          field: GenRecordField60
          rpcValue:
          conversionValue:
    RECORD_FIELD_GROUP_1:
      columns:
        RECORD_FIELD_1_STRING_1:
          field: GenRecordField1String1
          rpcValue:
          conversionValue:
        RECORD_FIELD_1_STRING_2:
          field: GenRecordField1String2
          rpcValue:
          conversionValue:
        RECORD_FIELD_1_STRING_3:
        ...
    RECORD_FIELD_GROUP_2:
      columns:
        RECORD_FIELD_2_STRING_1:
          field: GenRecordField2String1
          rpcValue:
          conversionValue:
        RECORD_FIELD_2_STRING_2:
        ...
Comments or questions about this documentation? Contact us for support!