BZ1989549-Fixed keepalived-ipfailover image URL

// Module included in the following assemblies:
//
// * networking/configuring-ipfailover.adoc

[id="nw-ipfailover-configuration_{context}"]
= Configuring IP failover

As a cluster administrator, you can configure IP failover on an entire cluster, or on a subset of nodes, as defined by the label selector. You can also configure multiple IP failover deployment configurations in your cluster, where each one is independent of the others.

The IP failover deployment configuration ensures that a failover pod runs on each of the nodes matching the constraints or the label used.

This pod runs Keepalived, which can monitor an endpoint and use Virtual Router Redundancy Protocol (VRRP) to fail over the virtual IP (VIP) from one node to another if the first node cannot reach the service or endpoint.

For production use, set a `selector` that selects at least two nodes, and set `replicas` equal to the number of selected nodes.

.Prerequisites

* You are logged in to the cluster with a user with `cluster-admin` privileges.
* You created a pull secret.

.Procedure

//. Create an {product-title} pull secret
//+
. Create an IP failover service account:
+
[source,terminal]
----
$ oc create sa ipfailover
----
+
. Update security context constraints (SCC) for `hostNetwork`:
+
[source,terminal]
----
$ oc adm policy add-scc-to-user privileged -z ipfailover
$ oc adm policy add-scc-to-user hostnetwork -z ipfailover
----
+
. Create a deployment YAML file to configure IP failover:
+
.Example deployment YAML for IP failover configuration
[source,yaml]
----
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ipfailover-keepalived <1>
  labels:
    ipfailover: hello-openshift
spec:
  strategy:
    type: Recreate
  replicas: 2
  selector:
    matchLabels:
      ipfailover: hello-openshift
  template:
    metadata:
      labels:
        ipfailover: hello-openshift
    spec:
      serviceAccountName: ipfailover
      privileged: true
      hostNetwork: true
      nodeSelector:
        node-role.kubernetes.io/worker: ""
      containers:
      - name: openshift-ipfailover
        image: quay.io/openshift/origin-keepalived-ipfailover
        ports:
        - containerPort: 63000
          hostPort: 63000
        imagePullPolicy: IfNotPresent
        securityContext:
          privileged: true
        volumeMounts:
        - name: lib-modules
          mountPath: /lib/modules
          readOnly: true
        - name: host-slash
          mountPath: /host
          readOnly: true
          mountPropagation: HostToContainer
        - name: etc-sysconfig
          mountPath: /etc/sysconfig
          readOnly: true
        - name: config-volume
          mountPath: /etc/keepalive
        env:
        - name: OPENSHIFT_HA_CONFIG_NAME
          value: "ipfailover"
        - name: OPENSHIFT_HA_VIRTUAL_IPS <2>
          value: "1.1.1.1-2"
        - name: OPENSHIFT_HA_VIP_GROUPS <3>
          value: "10"
        - name: OPENSHIFT_HA_NETWORK_INTERFACE <4>
          value: "ens3" #The host interface to assign the VIPs
        - name: OPENSHIFT_HA_MONITOR_PORT <5>
          value: "30060"
        - name: OPENSHIFT_HA_VRRP_ID_OFFSET <6>
          value: "0"
        - name: OPENSHIFT_HA_REPLICA_COUNT <7>
          value: "2" #Must match the number of replicas in the deployment
        - name: OPENSHIFT_HA_USE_UNICAST
          value: "false"
        #- name: OPENSHIFT_HA_UNICAST_PEERS
          #value: "10.0.148.40,10.0.160.234,10.0.199.110"
        - name: OPENSHIFT_HA_IPTABLES_CHAIN <8>
          value: "INPUT"
        #- name: OPENSHIFT_HA_NOTIFY_SCRIPT <9>
        #  value: /etc/keepalive/mynotifyscript.sh
        - name: OPENSHIFT_HA_CHECK_SCRIPT <10>
          value: "/etc/keepalive/mycheckscript.sh"
        - name: OPENSHIFT_HA_PREEMPTION <11>
          value: "preempt_delay 300"
        - name: OPENSHIFT_HA_CHECK_INTERVAL <12>
          value: "2"
        livenessProbe:
          initialDelaySeconds: 10
          exec:
            command:
            - pgrep
            - keepalived
      volumes:
      - name: lib-modules
        hostPath:
          path: /lib/modules
      - name: host-slash
        hostPath:
          path: /
      - name: etc-sysconfig
        hostPath:
          path: /etc/sysconfig
      # config-volume contains the check script
      # created with `oc create configmap keepalived-checkscript --from-file=mycheckscript.sh`
      - configMap:
          defaultMode: 0755
          name: keepalived-checkscript
        name: config-volume
      imagePullSecrets:
        - name: openshift-pull-secret <13>
----
<1> The name of the IP failover deployment.
<2> The list of IP address ranges to replicate. This must be provided. For example, `1.2.3.4-6,1.2.3.9`.
<3> The number of groups to create for VRRP. If not set, a group is created for each virtual IP range specified with the `OPENSHIFT_HA_VIP_GROUPS` variable.
<4> The interface name that IP failover uses to send VRRP traffic. By default, `eth0` is used.
<5> The IP failover pod tries to open a TCP connection to this port on each VIP. If connection is established, the service is considered to be running. If this port is set to `0`, the test always passes. The default value is `80`.
<6> The offset value used to set the virtual router IDs. Using different offset values allows multiple IP failover configurations to exist within the same cluster. The default offset is `0`, and the allowed range is `0` through `255`.
<7> The number of replicas to create. This must match `spec.replicas` value in IP failover deployment configuration. The default value is `2`.
<8> The name of the `iptables` chain to automatically add an `iptables` rule to allow the VRRP traffic on. If the value is not set, an `iptables` rule is not added. If the chain does not exist, it is not created, and Keepalived operates in unicast mode. The default is `INPUT`.
<9> The full path name in the pod file system of a script that is run whenever the state changes.
<10> The full path name in the pod file system of a script that is periodically run to verify the application is operating.
<11> The strategy for handling a new higher priority host. The default value is `preempt_delay 300`, which causes a Keepalived instance to take over a VIP after 5 minutes if a lower-priority master is holding the VIP.
<12> The period, in seconds, that the check script is run. The default value is `2`.
<13> Create the pull secret before creating the deployment, otherwise you will get an error when creating the deployment.
////
+
.Example service YAML for IP failover configuration
[source,yaml]
----
apiVersion: v1
kind: Service
metadata:
  name: ipfailover-keepalived-service
spec:
  ports:
    - port: 1985
      targetPort: 1985
      name: todo
    - port: 112
      targetPort: 112
      name: vrrp
  selector:
    ipfailover: hello-openshift
  externalIPs:
  - 1.1.1.1
  - 1.1.1.2
----
////

// Module included in the following assemblies:
//
// * networking/configuring-ipfailover.adoc

[id="nw-ipfailover-configuration_{context}"]
= Configuring IP failover

As a cluster administrator, you can configure IP failover on an entire cluster, or on a subset of nodes, as defined by the label selector. You can also configure multiple IP failover deployment configurations in your cluster, where each one is independent of the others.

The IP failover deployment configuration ensures that a failover pod runs on each of the nodes matching the constraints or the label used.

This pod runs Keepalived, which can monitor an endpoint and use Virtual Router Redundancy Protocol (VRRP) to fail over the virtual IP (VIP) from one node to another if the first node cannot reach the service or endpoint.

For production use, set a `selector` that selects at least two nodes, and set `replicas` equal to the number of selected nodes.

.Prerequisites

* You are logged in to the cluster with a user with `cluster-admin` privileges.
* You created a pull secret.

.Procedure

//. Create an {product-title} pull secret
//+
. Create an IP failover service account:
+
[source,terminal]
----
$ oc create sa ipfailover
----
+
. Update security context constraints (SCC) for `hostNetwork`:
+
[source,terminal]
----
$ oc adm policy add-scc-to-user privileged -z ipfailover
$ oc adm policy add-scc-to-user hostnetwork -z ipfailover
----
+
. Create a deployment YAML file to configure IP failover:
+
.Example deployment YAML for IP failover configuration
[source,yaml]
----
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ipfailover-keepalived <1>
  labels:
    ipfailover: hello-openshift
spec:
  strategy:
    type: Recreate
  replicas: 2
  selector:
    matchLabels:
      ipfailover: hello-openshift
  template:
    metadata:
      labels:
        ipfailover: hello-openshift
    spec:
      serviceAccountName: ipfailover
      privileged: true
      hostNetwork: true
      nodeSelector:
        node-role.kubernetes.io/worker: ""
      containers:
      - name: openshift-ipfailover
        image: quay.io/openshift/ose-keepalived-ipfailover:latest
        ports:
        - containerPort: 63000
          hostPort: 63000
        imagePullPolicy: IfNotPresent
        securityContext:
          privileged: true
        volumeMounts:
        - name: lib-modules
          mountPath: /lib/modules
          readOnly: true
        - name: host-slash
          mountPath: /host
          readOnly: true
          mountPropagation: HostToContainer
        - name: etc-sysconfig
          mountPath: /etc/sysconfig
          readOnly: true
        - name: config-volume
          mountPath: /etc/keepalive
        env:
        - name: OPENSHIFT_HA_CONFIG_NAME
          value: "ipfailover"
        - name: OPENSHIFT_HA_VIRTUAL_IPS <2>
          value: "1.1.1.1-2"
        - name: OPENSHIFT_HA_VIP_GROUPS <3>
          value: "10"
        - name: OPENSHIFT_HA_NETWORK_INTERFACE <4>
          value: "ens3" #The host interface to assign the VIPs
        - name: OPENSHIFT_HA_MONITOR_PORT <5>
          value: "30060"
        - name: OPENSHIFT_HA_VRRP_ID_OFFSET <6>
          value: "0"
        - name: OPENSHIFT_HA_REPLICA_COUNT <7>
          value: "2" #Must match the number of replicas in the deployment
        - name: OPENSHIFT_HA_USE_UNICAST
          value: "false"
        #- name: OPENSHIFT_HA_UNICAST_PEERS
          #value: "10.0.148.40,10.0.160.234,10.0.199.110"
        - name: OPENSHIFT_HA_IPTABLES_CHAIN <8>
          value: "INPUT"
        #- name: OPENSHIFT_HA_NOTIFY_SCRIPT <9>
        #  value: /etc/keepalive/mynotifyscript.sh
        - name: OPENSHIFT_HA_CHECK_SCRIPT <10>
          value: "/etc/keepalive/mycheckscript.sh"
        - name: OPENSHIFT_HA_PREEMPTION <11>
          value: "preempt_delay 300"
        - name: OPENSHIFT_HA_CHECK_INTERVAL <12>
          value: "2"
        livenessProbe:
          initialDelaySeconds: 10
          exec:
            command:
            - pgrep
            - keepalived
      volumes:
      - name: lib-modules
        hostPath:
          path: /lib/modules
      - name: host-slash
        hostPath:
          path: /
      - name: etc-sysconfig
        hostPath:
          path: /etc/sysconfig
      # config-volume contains the check script
      # created with `oc create configmap keepalived-checkscript --from-file=mycheckscript.sh`
      - configMap:
          defaultMode: 0755
          name: keepalived-checkscript
        name: config-volume
      imagePullSecrets:
        - name: openshift-pull-secret <13>
----
<1> The name of the IP failover deployment.
<2> The list of IP address ranges to replicate. This must be provided. For example, `1.2.3.4-6,1.2.3.9`.
<3> The number of groups to create for VRRP. If not set, a group is created for each virtual IP range specified with the `OPENSHIFT_HA_VIP_GROUPS` variable.
<4> The interface name that IP failover uses to send VRRP traffic. By default, `eth0` is used.
<5> The IP failover pod tries to open a TCP connection to this port on each VIP. If connection is established, the service is considered to be running. If this port is set to `0`, the test always passes. The default value is `80`.
<6> The offset value used to set the virtual router IDs. Using different offset values allows multiple IP failover configurations to exist within the same cluster. The default offset is `0`, and the allowed range is `0` through `255`.
<7> The number of replicas to create. This must match `spec.replicas` value in IP failover deployment configuration. The default value is `2`.
<8> The name of the `iptables` chain to automatically add an `iptables` rule to allow the VRRP traffic on. If the value is not set, an `iptables` rule is not added. If the chain does not exist, it is not created, and Keepalived operates in unicast mode. The default is `INPUT`.
<9> The full path name in the pod file system of a script that is run whenever the state changes.
<10> The full path name in the pod file system of a script that is periodically run to verify the application is operating.
<11> The strategy for handling a new higher priority host. The default value is `preempt_delay 300`, which causes a Keepalived instance to take over a VIP after 5 minutes if a lower-priority master is holding the VIP.
<12> The period, in seconds, that the check script is run. The default value is `2`.
<13> Create the pull secret before creating the deployment, otherwise you will get an error when creating the deployment.
////
+
.Example service YAML for IP failover configuration
[source,yaml]
----
apiVersion: v1
kind: Service
metadata:
  name: ipfailover-keepalived-service
spec:
  ports:
    - port: 1985
      targetPort: 1985
      name: todo
    - port: 112
      targetPort: 112
      name: vrrp
  selector:
    ipfailover: hello-openshift
  externalIPs:
  - 1.1.1.1
  - 1.1.1.2
----
////


add link to deref

add link to deref

= Clojure Deref (Nov 23, 2022)
Alex Miller
2022-11-23
:jbake-type: post

ifdef::env-github,env-browser[:outfilesuffix: .adoc]

Welcome to the Clojure Deref! This is a weekly link/news roundup for the Clojure ecosystem. (https://twitter.com/ClojureDeref[@ClojureDeref] https://clojure.org/feed.xml[RSS])

== Highlights

In this week of thanks, thank you to the Clojure community! It is a pleasure to present your work every week here and always a surprise how much the community does every single week.

== Podcasts and videos

* https://cognitect.com/cognicast/172[Janet A Carr - Cognicast Episode 172] - Cognicast
* https://www.youtube.com/watch?v=AYKIR1oh62Y[#1: Michiel Borkent @borkdude] - Show Me Your REPL
* https://clojure.stream/podcast[E84 Exoscale with Pierre-Yves Ritschard] - ClojureStream Podcast with Jacek Schae
* https://www.youtube.com/watch?v=B7_3hVF8zSc[Clojure defpure news 📰 filter-stack-trace for test errors] - Fred Overflow
* https://www.youtube.com/watch?v=2hBl31QP9Pc[Clojure and the Functional Paradigm] - Codurance

== Blogs and articles

* https://building.nubank.com.br/talk-james-gosling-java-at-nubank/[A mind-blowing conversation with James Gosling, Java’s father] - Building Nubank
* https://andreyorst.gitlab.io/posts/2022-11-21-clojures-coreasync-pipeline-async-off-by-two-error-explained/[Clojure's core.async pipeline-async off-by-two error explained] - Andrey Listopadov
* https://clojure.stream/workshops/babashka[Babashka Workshop] - ClojureStream

== Libraries and tools

New releases and tools this week:

* https://github.com/Datomic/dev.datafy[dev.datafy] 0.1 - Dev-time datafy and nav
* https://github.com/pedestal/pedestal[pedestal] 0.5.11-beta-1 - The Pedestal Server-side Libraries
* https://github.com/liquidz/antq[antq] 2.2.962 - Point out your outdated dependencies
* https://github.com/borkdude/edamame[edamame] 1.0.16 - Configurable EDN/Clojure parser with location metadata
* https://github.com/babashka/nbb[nbb] 1.0.136 - Scripting in Clojure on Node.js using SCI
* https://github.com/clj-commons/hickory[hickory] 0.7.2 - HTML as data
* https://github.com/liquidz/antq[antq] 2.2.962 - Point out your outdated dependencies
* https://github.com/fulcrologic/fulcro-rad[fulcro-rad] 1.3.9 - Fulcro Rapid Application Development
* https://github.com/fulcrologic/fulcro-rad-semantic-ui[fulcro-rad-semantic-ui] 1.2.18 - Semantic UI Rendering Plugin for RAD
* https://github.com/BetterThanTomorrow/calva[calva] https://github.com/BetterThanTomorrow/calva/releases/tag/v2.0.320[2.0.320] - Clojure & ClojureScript Interactive Programming for VS Code
* https://github.com/BetterThanTomorrow/joyride[joyride] 0.0.23 - Making VS Code Hackable since 2022
* https://github.com/babashka/scittle[scittle] 0.4.11 - Execute Clojure(Script) directly from browser script tags via SCI
* https://git.sr.ht/~jomco/select-tree[select-tree] 0.1.0 - Clojure library to recursively select subtrees of collections

= Clojure Deref (Nov 23, 2022)
Alex Miller
2022-11-23
:jbake-type: post

ifdef::env-github,env-browser[:outfilesuffix: .adoc]

Welcome to the Clojure Deref! This is a weekly link/news roundup for the Clojure ecosystem. (https://twitter.com/ClojureDeref[@ClojureDeref] https://clojure.org/feed.xml[RSS])

== Highlights

In this week of thanks, thank you to the Clojure community! It is a pleasure to present your work every week here and always a surprise how much the community does every single week.

== Podcasts and videos

* https://cognitect.com/cognicast/172[Janet A Carr - Cognicast Episode 172] - Cognicast
* https://www.youtube.com/watch?v=AYKIR1oh62Y[#1: Michiel Borkent @borkdude] - Show Me Your REPL
* https://www.youtube.com/watch?v=B7_3hVF8zSc[Clojure defpure news 📰 filter-stack-trace for test errors] - Fred Overflow
* https://www.youtube.com/watch?v=2hBl31QP9Pc[Clojure and the Functional Paradigm] - Codurance

== Blogs and articles

* https://building.nubank.com.br/talk-james-gosling-java-at-nubank/[A mind-blowing conversation with James Gosling, Java’s father] - Building Nubank
* https://andreyorst.gitlab.io/posts/2022-11-21-clojures-coreasync-pipeline-async-off-by-two-error-explained/[Clojure's core.async pipeline-async off-by-two error explained] - Andrey Listopadov
* https://clojure.stream/workshops/babashka[Babashka Workshop] - ClojureStream

== Libraries and tools

New releases and tools this week:

* https://github.com/Datomic/dev.datafy[dev.datafy] 0.1 - Dev-time datafy and nav
* https://github.com/pedestal/pedestal[pedestal] 0.5.11-beta-1 - The Pedestal Server-side Libraries
* https://github.com/liquidz/antq[antq] 2.2.962 - Point out your outdated dependencies
* https://github.com/borkdude/edamame[edamame] 1.0.16 - Configurable EDN/Clojure parser with location metadata
* https://github.com/babashka/nbb[nbb] 1.0.136 - Scripting in Clojure on Node.js using SCI
* https://github.com/clj-commons/hickory[hickory] 0.7.2 - HTML as data
* https://github.com/liquidz/antq[antq] 2.2.962 - Point out your outdated dependencies
* https://github.com/fulcrologic/fulcro-rad[fulcro-rad] 1.3.9 - Fulcro Rapid Application Development
* https://github.com/fulcrologic/fulcro-rad-semantic-ui[fulcro-rad-semantic-ui] 1.2.18 - Semantic UI Rendering Plugin for RAD
* https://github.com/BetterThanTomorrow/calva[calva] https://github.com/BetterThanTomorrow/calva/releases/tag/v2.0.320[2.0.320] - Clojure & ClojureScript Interactive Programming for VS Code
* https://github.com/BetterThanTomorrow/joyride[joyride] 0.0.23 - Making VS Code Hackable since 2022
* https://github.com/babashka/scittle[scittle] 0.4.11 - Execute Clojure(Script) directly from browser script tags via SCI
* https://git.sr.ht/~jomco/select-tree[select-tree] 0.1.0 - Clojure library to recursively select subtrees of collections


OSD: Fix directions to cluster logging instance

I was walking through these instructions today and had to do things a
bit differently from what the doc said. Updated accordingly.

// Module included in the following assemblies:
//
// * logging/dedicated-cluster-deploying.adoc

[id="dedicated-cluster-install-deploy"]

= Installing the Cluster Logging and Elasticsearch Operators

You can use the {product-title} console to install cluster logging by deploying instances of
the Cluster Logging and Elasticsearch Operators.  The Cluster Logging Operator
creates and manages the components of the logging stack.  The Elasticsearch Operator
creates and manages the Elasticsearch cluster used by cluster logging.

[NOTE]
====
The {product-title} cluster logging solution requires that you install both the
Cluster Logging Operator and Elasticsearch Operator. When you deploy an instance
of the Cluster Logging Operator, it also deploys an instance of the Elasticsearch
Operator.
====

Your OpenShift Dedicated cluster includes 600 GiB of persistent storage that is
exclusively available for deploying Elasticsearch for cluster logging.

Elasticsearch is a memory-intensive application. Each Elasticsearch node needs
8G of memory for both memory requests and limits. Each Elasticsearch node can
operate with a lower memory setting, though this is not recommended for
production deployments.

.Procedure

. Install the Elasticsearch Operator from the OperatorHub:

.. In the {product-title} web console, click *Operators* -> *OperatorHub*.

.. Choose *Elasticsearch* from the list of available Operators, and click *Install*.

.. On the *Create Operator Subscription* page, under *A specific namespace on the cluster* select *openshift-logging*.
Then, click *Subscribe*.

. Install the Cluster Logging Operator from the OperatorHub:

.. In the {product-title} web console, click *Operators* -> *OperatorHub*.

.. Choose  *Cluster Logging* from the list of available Operators, and click *Install*.

.. On the *Create Operator Subscription* page, under *A specific namespace on the cluster* select *openshift-logging*.
Then, click *Subscribe*.

. Verify the operator installations:

.. Switch to the *Operators* → *Installed Operators* page.

.. Ensure that *Cluster Logging* and *Elasticsearch* Operators are listed in the
*openshift-logging* project with a *Status* of *InstallSucceeded*.
+
[NOTE]
====
During installation an operator might display a *Failed* status. If the operator then installs with an *InstallSucceeded* message,
you can safely ignore the *Failed* message.
====
+
If either operator does not appear as installed, to troubleshoot further:
+
* Switch to the *Operators* → *Installed Operators* page and inspect
the *Status* column for any errors or failures.
* Switch to the *Workloads* → *Pods* page and check the logs in each Pod in the
`openshift-logging` project that is reporting issues.

. Create and deploy a cluster logging instance:

.. Switch to the *Operators* → *Installed Operators* page.

.. Click the installed *Cluster Logging* Operator.

.. Under the *Details* tab, in the *Provided APIs* section, in the
*Cluster Logging* box, click *Create Instance* . Select the *YAML View*
radio button and paste the following YAML definition into the window
that displays.
+
.Cluster Logging Custom Resource (CR)
[source,yaml]
----
apiVersion: "logging.openshift.io/v1"
kind: "ClusterLogging"
metadata:
  name: "instance"
  namespace: "openshift-logging"
spec:
  managementState: "Managed"
  logStore:
    type: "elasticsearch"
    elasticsearch:
      nodeCount: 3
      storage:
        storageClassName: "gp2"
        size: "200Gi"
      redundancyPolicy: "SingleRedundancy"
      nodeSelector:
        node-role.kubernetes.io/worker: ""
      resources:
        requests:
          memory: 8G
  visualization:
    type: "kibana"
    kibana:
      replicas: 1
      nodeSelector:
        node-role.kubernetes.io/worker: ""
  curation:
    type: "curator"
    curator:
      schedule: "15 * * * *"
      nodeSelector:
        node-role.kubernetes.io/worker: ""
  collection:
    logs:
      type: "fluentd"
      fluentd: {}
      nodeSelector:
        node-role.kubernetes.io/worker: ""
----

.. Click *Create* to deploy the logging instance, which creates the Cluster
Logging and Elasticsearch Custom Resources.

. Verify that the Pods for the Cluster Logging instance deployed:

.. Switch to the *Workloads* → *Pods* page.

.. Select the *openshift-logging* project.
+
You should see several pods for cluster logging, Elasticsearch, Fluentd, and Kibana similar to the following list:
+
* cluster-logging-operator-cb795f8dc-xkckc
* elasticsearch-cdm-b3nqzchd-1-5c6797-67kfz
* elasticsearch-cdm-b3nqzchd-2-6657f4-wtprv
* elasticsearch-cdm-b3nqzchd-3-588c65-clg7g
* fluentd-2c7dg
* fluentd-9z7kk
* fluentd-br7r2
* fluentd-fn2sb
* fluentd-pb2f8
* fluentd-zqgqx
* kibana-7fb4fd4cc9-bvt4p

. Access the Cluster Logging interface, *Kibana*, from the *Monitoring* →
*Logging* page of the {product-title} web console.

// Module included in the following assemblies:
//
// * logging/dedicated-cluster-deploying.adoc

[id="dedicated-cluster-install-deploy"]

= Installing the Cluster Logging and Elasticsearch Operators

You can use the {product-title} console to install cluster logging by deploying instances of
the Cluster Logging and Elasticsearch Operators.  The Cluster Logging Operator
creates and manages the components of the logging stack.  The Elasticsearch Operator
creates and manages the Elasticsearch cluster used by cluster logging.

[NOTE]
====
The {product-title} cluster logging solution requires that you install both the
Cluster Logging Operator and Elasticsearch Operator. When you deploy an instance
of the Cluster Logging Operator, it also deploys an instance of the Elasticsearch
Operator.
====

Your OpenShift Dedicated cluster includes 600 GiB of persistent storage that is
exclusively available for deploying Elasticsearch for cluster logging.

Elasticsearch is a memory-intensive application. Each Elasticsearch node needs
8G of memory for both memory requests and limits. Each Elasticsearch node can
operate with a lower memory setting, though this is not recommended for
production deployments.

.Procedure

. Install the Elasticsearch Operator from the OperatorHub:

.. In the {product-title} web console, click *Operators* -> *OperatorHub*.

.. Choose *Elasticsearch* from the list of available Operators, and click *Install*.

.. On the *Create Operator Subscription* page, under *A specific namespace on the cluster* select *openshift-logging*.
Then, click *Subscribe*.

. Install the Cluster Logging Operator from the OperatorHub:

.. In the {product-title} web console, click *Operators* -> *OperatorHub*.

.. Choose  *Cluster Logging* from the list of available Operators, and click *Install*.

.. On the *Create Operator Subscription* page, under *A specific namespace on the cluster* select *openshift-logging*.
Then, click *Subscribe*.

. Verify the operator installations:

.. Switch to the *Operators* → *Installed Operators* page.

.. Ensure that *Cluster Logging* and *Elasticsearch* Operators are listed in the
*openshift-logging* project with a *Status* of *InstallSucceeded*.
+
[NOTE]
====
During installation an operator might display a *Failed* status. If the operator then installs with an *InstallSucceeded* message,
you can safely ignore the *Failed* message.
====
+
If either operator does not appear as installed, to troubleshoot further:
+
* Switch to the *Operators* → *Installed Operators* page and inspect
the *Status* column for any errors or failures.
* Switch to the *Workloads* → *Pods* page and check the logs in each Pod in the
`openshift-logging` project that is reporting issues.

. Create and deploy a cluster logging instance:

.. Switch to the *Operators* → *Installed Operators* page.

.. Click the installed *Cluster Logging* Operator.

.. Under the *Overview* tab, click *Create Instance* . Paste the following YAML
definition into the window that displays.
+
.Cluster Logging Custom Resource (CR)
[source,yaml]
----
apiVersion: "logging.openshift.io/v1"
kind: "ClusterLogging"
metadata:
  name: "instance"
  namespace: "openshift-logging"
spec:
  managementState: "Managed"
  logStore:
    type: "elasticsearch"
    elasticsearch:
      nodeCount: 3
      storage:
        storageClassName: "gp2"
        size: "200Gi"
      redundancyPolicy: "SingleRedundancy"
      nodeSelector:
        node-role.kubernetes.io/worker: ""
      resources:
        requests:
          memory: 8G
  visualization:
    type: "kibana"
    kibana:
      replicas: 1
      nodeSelector:
        node-role.kubernetes.io/worker: ""
  curation:
    type: "curator"
    curator:
      schedule: "15 * * * *"
      nodeSelector:
        node-role.kubernetes.io/worker: ""
  collection:
    logs:
      type: "fluentd"
      fluentd: {}
      nodeSelector:
        node-role.kubernetes.io/worker: ""
----

.. Click *Create* to deploy the logging instance, which creates the Cluster
Logging and Elasticsearch Custom Resources.

. Verify that the Pods for the Cluster Logging instance deployed:

.. Switch to the *Workloads* → *Pods* page.

.. Select the *openshift-logging* project.
+
You should see several pods for cluster logging, Elasticsearch, Fluentd, and Kibana similar to the following list:
+
* cluster-logging-operator-cb795f8dc-xkckc
* elasticsearch-cdm-b3nqzchd-1-5c6797-67kfz
* elasticsearch-cdm-b3nqzchd-2-6657f4-wtprv
* elasticsearch-cdm-b3nqzchd-3-588c65-clg7g
* fluentd-2c7dg
* fluentd-9z7kk
* fluentd-br7r2
* fluentd-fn2sb
* fluentd-pb2f8
* fluentd-zqgqx
* kibana-7fb4fd4cc9-bvt4p

. Access the Cluster Logging interface, *Kibana*, from the *Monitoring* →
*Logging* page of the {product-title} web console.


Update PasswordEncoder declaration

Update PasswordEncoder declaration

Closes gh-10910

[[crypto]]
= Spring Security Crypto Module

[[spring-security-crypto-introduction]]
The Spring Security Crypto module provides support for symmetric encryption, key generation, and password encoding.
The code is distributed as part of the core module but has no dependencies on any other Spring Security (or Spring) code.

[[spring-security-crypto-encryption]]
== Encryptors
The {security-api-url}org/springframework/security/crypto/encrypt/Encryptors.html[`Encryptors`] class provides factory methods for constructing symmetric encryptors.
This class lets you create {security-api-url}org/springframework/security/crypto/encrypt/BytesEncryptor.html[`BytesEncryptor`] instances to encrypt data in raw `byte[]` form.
You can also construct {security-api-url}org/springframework/security/crypto/encrypt/TextEncryptor.html[TextEncryptor] instances to encrypt text strings.
Encryptors are thread-safe.

[NOTE]
====
Both `BytesEncryptor` and `TextEncryptor` are interfaces. `BytesEncryptor` has multiple implementations.
====

[[spring-security-crypto-encryption-bytes]]
=== BytesEncryptor
You can use the `Encryptors.stronger` factory method to construct a `BytesEncryptor`:

.BytesEncryptor
====
.Java
[source,java,role="primary"]
----
Encryptors.stronger("password", "salt");
----

.Kotlin
[source,kotlin,role="secondary"]
----
Encryptors.stronger("password", "salt")
----
====

The `stronger` encryption method creates an encryptor by using 256-bit AES encryption with
Galois Counter Mode (GCM).
It derives the secret key by using PKCS #5's PBKDF2 (Password-Based Key Derivation Function #2).
This method requires Java 6.
The password used to generate the `SecretKey` should be kept in a secure place and should not be shared.
The salt is used to prevent dictionary attacks against the key in the event that your encrypted data is compromised.
A 16-byte random initialization vector is also applied so that each encrypted message is unique.

The provided salt should be in hex-encoded String form, be random, and be at least 8 bytes in length.
You can generate such a salt by using a `KeyGenerator`:

.Generating a key
====
.Java
[source,java,role="primary"]
----
String salt = KeyGenerators.string().generateKey(); // generates a random 8-byte salt that is then hex-encoded
----

.Kotlin
[source,kotlin,role="secondary"]
----
val salt = KeyGenerators.string().generateKey() // generates a random 8-byte salt that is then hex-encoded
----
====

You can also use the `standard` encryption method, which is 256-bit AES in Cipher Block Chaining (CBC) Mode.
This mode is not https://en.wikipedia.org/wiki/Authenticated_encryption[authenticated] and does not provide any
guarantees about the authenticity of the data.
For a more secure alternative, use `Encryptors.stronger`.

[[spring-security-crypto-encryption-text]]
=== TextEncryptor
You can use the `Encryptors.text` factory method to construct a standard TextEncryptor:

.TextEncryptor
====
.Java
[source,java,role="primary"]
----
Encryptors.text("password", "salt");
----

.Kotlin
[source,kotlin,role="secondary"]
----
Encryptors.text("password", "salt")
----
====

A `TextEncryptor` uses a standard `BytesEncryptor` to encrypt text data.
Encrypted results are returned as hex-encoded strings for easy storage on the filesystem or in a database.

You can use the `Encryptors.queryableText` factory method to construct a "`queryable`" `TextEncryptor`:

.Queryable TextEncryptor
====
.Java
[source,java,role="primary"]
----
Encryptors.queryableText("password", "salt");
----

.Kotlin
[source,kotlin,role="secondary"]
----
Encryptors.queryableText("password", "salt")
----
====

The difference between a queryable `TextEncryptor` and a standard `TextEncryptor` has to do with initialization vector (IV) handling.
The IV used in a queryable `TextEncryptor.encrypt` operation is shared, or constant, and is not randomly generated.
This means the same text encrypted multiple times always produces the same encryption result.
This is less secure but necessary for encrypted data that needs to be queried against.
An example of queryable encrypted text would be an OAuth `apiKey`.

[[spring-security-crypto-keygenerators]]
== Key Generators
The {security-api-url}org/springframework/security/crypto/keygen/KeyGenerators.html[`KeyGenerators`] class provides a number of convenience factory methods for constructing different types of key generators.
By using this class, you can create a {security-api-url}org/springframework/security/crypto/keygen/BytesKeyGenerator.html[`BytesKeyGenerator`] to generate `byte[]` keys.
You can also construct a {security-api-url}org/springframework/security/crypto/keygen/StringKeyGenerator.html`[StringKeyGenerator]` to generate string keys.
`KeyGenerators` is a thread-safe class.

=== BytesKeyGenerator
You can use the `KeyGenerators.secureRandom` factory methods to generate a `BytesKeyGenerator` backed by a `SecureRandom` instance:

.BytesKeyGenerator
====
.Java
[source,java,role="primary"]
----
BytesKeyGenerator generator = KeyGenerators.secureRandom();
byte[] key = generator.generateKey();
----

.Kotlin
[source,kotlin,role="secondary"]
----
val generator = KeyGenerators.secureRandom()
val key = generator.generateKey()
----
====

The default key length is 8 bytes.
A `KeyGenerators.secureRandom` variant provides control over the key length:

.KeyGenerators.secureRandom
====
.Java
[source,java,role="primary"]
----
KeyGenerators.secureRandom(16);
----

.Kotlin
[source,kotlin,role="secondary"]
----
KeyGenerators.secureRandom(16)
----
====

Use the `KeyGenerators.shared` factory method to construct a BytesKeyGenerator that always returns the same key on every invocation:

.KeyGenerators.shared
====
.Java
[source,java,role="primary"]
----
KeyGenerators.shared(16);
----

.Kotlin
[source,kotlin,role="secondary"]
----
KeyGenerators.shared(16)
----
====

=== StringKeyGenerator
You can use the `KeyGenerators.string` factory method to construct an 8-byte, `SecureRandom` `KeyGenerator` that hex-encodes each key as a `String`:

.StringKeyGenerator
====
.Java
[source,java,role="primary"]
----
KeyGenerators.string();
----

.Kotlin
[source,kotlin,role="secondary"]
----
KeyGenerators.string()
----
====

[[spring-security-crypto-passwordencoders]]
== Password Encoding
The password package of the `spring-security-crypto` module provides support for encoding passwords.
`PasswordEncoder` is the central service interface and has the following signature:

====
[source,java]
----
public interface PasswordEncoder {
	String encode(CharSequence rawPassword);

	boolean matches(CharSequence rawPassword, String encodedPassword);

	default boolean upgradeEncoding(String encodedPassword) {
		return false;
	}
}
----
====

The `matches` method returns true if the `rawPassword`, once encoded, equals the `encodedPassword`.
This method is designed to support password-based authentication schemes.

The `BCryptPasswordEncoder` implementation uses the widely supported "`bcrypt`" algorithm to hash the passwords.
Bcrypt uses a random 16-byte salt value and is a deliberately slow algorithm, to hinder password crackers.
You can tune the amount of work it does by using the `strength` parameter, which takes a value from 4 to 31.
The higher the value, the more work has to be done to calculate the hash.
The default value is `10`.
You can change this value in your deployed system without affecting existing passwords, as the value is also stored in the encoded hash.
The following example uses the `BCryptPasswordEncoder`:

.BCryptPasswordEncoder
====
.Java
[source,java,role="primary"]
----

// Create an encoder with strength 16
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16);
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
----

.Kotlin
[source,kotlin,role="secondary"]
----

// Create an encoder with strength 16
val encoder = BCryptPasswordEncoder(16)
val result: String = encoder.encode("myPassword")
assertTrue(encoder.matches("myPassword", result))
----
====

The `Pbkdf2PasswordEncoder` implementation uses PBKDF2 algorithm to hash the passwords.
To defeat password cracking, PBKDF2 is a deliberately slow algorithm and should be tuned to take about .5 seconds to verify a password on your system.
The following system uses the `Pbkdf2PasswordEncoder`:

.Pbkdf2PasswordEncoder
====
.Java
[source,java,role="primary"]
----
// Create an encoder with all the defaults
Pbkdf2PasswordEncoder encoder = new Pbkdf2PasswordEncoder();
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
----

.Kotlin
[source,kotlin,role="secondary"]
----
// Create an encoder with all the defaults
val encoder = Pbkdf2PasswordEncoder()
val result: String = encoder.encode("myPassword")
assertTrue(encoder.matches("myPassword", result))
----
====

[[crypto]]
= Spring Security Crypto Module

[[spring-security-crypto-introduction]]
The Spring Security Crypto module provides support for symmetric encryption, key generation, and password encoding.
The code is distributed as part of the core module but has no dependencies on any other Spring Security (or Spring) code.

[[spring-security-crypto-encryption]]
== Encryptors
The {security-api-url}org/springframework/security/crypto/encrypt/Encryptors.html[`Encryptors`] class provides factory methods for constructing symmetric encryptors.
This class lets you create {security-api-url}org/springframework/security/crypto/encrypt/BytesEncryptor.html[`BytesEncryptor`] instances to encrypt data in raw `byte[]` form.
You can also construct {security-api-url}org/springframework/security/crypto/encrypt/TextEncryptor.html[TextEncryptor] instances to encrypt text strings.
Encryptors are thread-safe.

[NOTE]
====
Both `BytesEncryptor` and `TextEncryptor` are interfaces. `BytesEncryptor` has multiple implementations.
====

[[spring-security-crypto-encryption-bytes]]
=== BytesEncryptor
You can use the `Encryptors.stronger` factory method to construct a `BytesEncryptor`:

.BytesEncryptor
====
.Java
[source,java,role="primary"]
----
Encryptors.stronger("password", "salt");
----

.Kotlin
[source,kotlin,role="secondary"]
----
Encryptors.stronger("password", "salt")
----
====

The `stronger` encryption method creates an encryptor by using 256-bit AES encryption with
Galois Counter Mode (GCM).
It derives the secret key by using PKCS #5's PBKDF2 (Password-Based Key Derivation Function #2).
This method requires Java 6.
The password used to generate the `SecretKey` should be kept in a secure place and should not be shared.
The salt is used to prevent dictionary attacks against the key in the event that your encrypted data is compromised.
A 16-byte random initialization vector is also applied so that each encrypted message is unique.

The provided salt should be in hex-encoded String form, be random, and be at least 8 bytes in length.
You can generate such a salt by using a `KeyGenerator`:

.Generating a key
====
.Java
[source,java,role="primary"]
----
String salt = KeyGenerators.string().generateKey(); // generates a random 8-byte salt that is then hex-encoded
----

.Kotlin
[source,kotlin,role="secondary"]
----
val salt = KeyGenerators.string().generateKey() // generates a random 8-byte salt that is then hex-encoded
----
====

You can also use the `standard` encryption method, which is 256-bit AES in Cipher Block Chaining (CBC) Mode.
This mode is not https://en.wikipedia.org/wiki/Authenticated_encryption[authenticated] and does not provide any
guarantees about the authenticity of the data.
For a more secure alternative, use `Encryptors.stronger`.

[[spring-security-crypto-encryption-text]]
=== TextEncryptor
You can use the `Encryptors.text` factory method to construct a standard TextEncryptor:

.TextEncryptor
====
.Java
[source,java,role="primary"]
----
Encryptors.text("password", "salt");
----

.Kotlin
[source,kotlin,role="secondary"]
----
Encryptors.text("password", "salt")
----
====

A `TextEncryptor` uses a standard `BytesEncryptor` to encrypt text data.
Encrypted results are returned as hex-encoded strings for easy storage on the filesystem or in a database.

You can use the `Encryptors.queryableText` factory method to construct a "`queryable`" `TextEncryptor`:

.Queryable TextEncryptor
====
.Java
[source,java,role="primary"]
----
Encryptors.queryableText("password", "salt");
----

.Kotlin
[source,kotlin,role="secondary"]
----
Encryptors.queryableText("password", "salt")
----
====

The difference between a queryable `TextEncryptor` and a standard `TextEncryptor` has to do with initialization vector (IV) handling.
The IV used in a queryable `TextEncryptor.encrypt` operation is shared, or constant, and is not randomly generated.
This means the same text encrypted multiple times always produces the same encryption result.
This is less secure but necessary for encrypted data that needs to be queried against.
An example of queryable encrypted text would be an OAuth `apiKey`.

[[spring-security-crypto-keygenerators]]
== Key Generators
The {security-api-url}org/springframework/security/crypto/keygen/KeyGenerators.html[`KeyGenerators`] class provides a number of convenience factory methods for constructing different types of key generators.
By using this class, you can create a {security-api-url}org/springframework/security/crypto/keygen/BytesKeyGenerator.html[`BytesKeyGenerator`] to generate `byte[]` keys.
You can also construct a {security-api-url}org/springframework/security/crypto/keygen/StringKeyGenerator.html`[StringKeyGenerator]` to generate string keys.
`KeyGenerators` is a thread-safe class.

=== BytesKeyGenerator
You can use the `KeyGenerators.secureRandom` factory methods to generate a `BytesKeyGenerator` backed by a `SecureRandom` instance:

.BytesKeyGenerator
====
.Java
[source,java,role="primary"]
----
BytesKeyGenerator generator = KeyGenerators.secureRandom();
byte[] key = generator.generateKey();
----

.Kotlin
[source,kotlin,role="secondary"]
----
val generator = KeyGenerators.secureRandom()
val key = generator.generateKey()
----
====

The default key length is 8 bytes.
A `KeyGenerators.secureRandom` variant provides control over the key length:

.KeyGenerators.secureRandom
====
.Java
[source,java,role="primary"]
----
KeyGenerators.secureRandom(16);
----

.Kotlin
[source,kotlin,role="secondary"]
----
KeyGenerators.secureRandom(16)
----
====

Use the `KeyGenerators.shared` factory method to construct a BytesKeyGenerator that always returns the same key on every invocation:

.KeyGenerators.shared
====
.Java
[source,java,role="primary"]
----
KeyGenerators.shared(16);
----

.Kotlin
[source,kotlin,role="secondary"]
----
KeyGenerators.shared(16)
----
====

=== StringKeyGenerator
You can use the `KeyGenerators.string` factory method to construct an 8-byte, `SecureRandom` `KeyGenerator` that hex-encodes each key as a `String`:

.StringKeyGenerator
====
.Java
[source,java,role="primary"]
----
KeyGenerators.string();
----

.Kotlin
[source,kotlin,role="secondary"]
----
KeyGenerators.string()
----
====

[[spring-security-crypto-passwordencoders]]
== Password Encoding
The password package of the `spring-security-crypto` module provides support for encoding passwords.
`PasswordEncoder` is the central service interface and has the following signature:

====
[source,java]
----
public interface PasswordEncoder {

String encode(String rawPassword);

boolean matches(String rawPassword, String encodedPassword);
}
----
====

The `matches` method returns true if the `rawPassword`, once encoded, equals the `encodedPassword`.
This method is designed to support password-based authentication schemes.

The `BCryptPasswordEncoder` implementation uses the widely supported "`bcrypt`" algorithm to hash the passwords.
Bcrypt uses a random 16-byte salt value and is a deliberately slow algorithm, to hinder password crackers.
You can tune the amount of work it does by using the `strength` parameter, which takes a value from 4 to 31.
The higher the value, the more work has to be done to calculate the hash.
The default value is `10`.
You can change this value in your deployed system without affecting existing passwords, as the value is also stored in the encoded hash.
The following example uses the `BCryptPasswordEncoder`:

.BCryptPasswordEncoder
====
.Java
[source,java,role="primary"]
----

// Create an encoder with strength 16
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16);
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
----

.Kotlin
[source,kotlin,role="secondary"]
----

// Create an encoder with strength 16
val encoder = BCryptPasswordEncoder(16)
val result: String = encoder.encode("myPassword")
assertTrue(encoder.matches("myPassword", result))
----
====

The `Pbkdf2PasswordEncoder` implementation uses PBKDF2 algorithm to hash the passwords.
To defeat password cracking, PBKDF2 is a deliberately slow algorithm and should be tuned to take about .5 seconds to verify a password on your system.
The following system uses the `Pbkdf2PasswordEncoder`:

.Pbkdf2PasswordEncoder
====
.Java
[source,java,role="primary"]
----
// Create an encoder with all the defaults
Pbkdf2PasswordEncoder encoder = new Pbkdf2PasswordEncoder();
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
----

.Kotlin
[source,kotlin,role="secondary"]
----
// Create an encoder with all the defaults
val encoder = Pbkdf2PasswordEncoder()
val result: String = encoder.encode("myPassword")
assertTrue(encoder.matches("myPassword", result))
----
====


fixed #89

fixed #89

:Author: Shinji KOBAYASHI
:Email: skoba@moss.gr.jp
:toc: right
:toclevels: 2
:pagenums:
:numberd:
:sectnums:
:imagesdir: ./figures
:linkcss:

=== 体温表モジュール
==== 目的と対象
日々の介護や看護で記録される体温表を記録するために使用される。

このモジュールにおいては、バイタルサインモジュールとあわせて、食事摂取量、排泄についての情報を扱っていく。想定されるユースケースは体温表に記載される各種情報である。

図に示すように、バイタルサインや摂食情報、排泄に関する情報は繰り返し記録される。

==== namespace宣言
このモジュールのnamespaceは以下のように宣言する。
[source, xml]
 xmlns:mmlFs="http://www.medxml.net/MML/v4/ContentModule/FlowSheet/1.0"

==== 文書ヘッダー情報 (docInfo) のモジュール個別仕様
===== docInfo
属性 contentModuleType に MML0005 テーブルより「flowsheet」を入力すること．

===== title
このモジュールは病棟あるいは介護施設などで日々記録される体温表を主なユースケースと考えている。したがって、レポートタイトルとしては「体温表」であることを前提とするが、病棟で慣用的に利用される「熱型表」「体温表」や「温度板」などが、タイトルとして使用されることも想定している。

属性の generationPurpose は，MML0007 テーブルより「flowsheet」 (体温表) と入力すること．

===== confirmDate
モジュール生成日であり，全体としての報告がなされた時刻を示す．

===== mmlCi:CreatorInfo
体温表モジュールでは、多職種にわたる複数の人間が観察した情報が一つの報告書に記載されることがある。最終的な記載者あるいは代表者が作成者情報として記録される。

.エレメント構造図
image::mmlfs.png[]

.エレメント一覧表
[options="header"]
|===
| |Elements|Attribute|Data types|Occurrence|TableId
|M23.|mmlFs:FlowSheetModule| | | |
|M23.1.|mmlFs:context| | | |
|M23.1.1.|mmlFs:facility| |string| |
| | |mmlFs:facilityCode|string|#REQUIRED|
| | |mmlFs:facilityCodeId|string|#REQUIRED|MML0027
|M23.1.2.|mmlFs:department| |string|?|
| | |mmlFs:depCode|string|#IMPLIED|MML0028
| | |mmlFs:depCodeId|string|#IMPLIED|
|M23.1.3.|mmlFs:ward| |string|?|
| | |mmlFs:wardCode|string|#IMPLIED|ユーザ指定
| | |mmlFs:wardCodeId|string|#IMPLIED|
|M23.1.4.|mmlFs:observer| |string|?|
| | |mmlFs:obsCode|string|#IMPLIED|ユーザ指定
| | |mmlFs:obsCodeId|string|#IMPLIED|
|M23.2.|mmlVs:VitalSignModule| | |*|
|M23.3.|mmlFs:intake| | |*|
|M23.3.1.|mmlFs:intakeType| |string| |mmlFs01
|M23.3.2.|mmlFs:intakeVolume| |decimal|?|
|M23.3.3.|mmlFs:intakeUnit| |string|?|mmlFs02
|M23.3.4.|mmlFs:intakePathway| |string|?|
|M23.3.5.|mmlFs:intakeStartTime| |dateTime|?|
|M23.3.6.|mmlFs:intakeEndTime| |dateTime|?|
|M23.3.7.|mmlFs:intakeMemo| |string|?|
|M23.4.|mmlFs:bodilyOutput| | |*|
|M23.4.1.|mmlFs:boType| |string| |mmlFs03
|M23.4.2.|mmlFs:boVolume| |decimal|?|
|M23.4.3.|mmlFs:boUnit| |string|?|mmlFs04
|M23.4.4.|mmlFs:boStatus| |string|?|
|M23.4.5.|mmlFs:boColor| |string|?|
|M23.4.6.|mmlFs:boPathway| |string|?|
|M23.4.7.|mmlFs:boStartTime| |dateTime|?|
|M23.4.8.|mmlFs:boEndTime| |dateTime|?|
|M23.4.9.|mmlFs:boMemo| |string|?|
|M23.4.10.|mmlFs:boFrequency| | |*|
|M23.4.10.1.|mmlFs:bofTimes| |decimal|?|
|M23.4.10.2.|mmlFs:bofPeriodStartTime| |dateTime|?|
|M23.4.10.3.|mmlFs:bofPeriodEndTime| |dateTime|?|
|M23.4.10.4.|mmlFs:bofMemo| |string|?|
|M23.5.|mmlFs:fsMemo| |string|?|
|===
Occurrenceなし：必ず1回出現，?： 0回もしくは1回出現，+： 1回以上出現，*： 0 回以上出現

#REQUIRED:必須属性，#IMPLIED:省略可能属性

==== エレメント解説
===== M23. mmlFs:FlowSheetModule
【内容】体温表モジュール

===== M23.1. mmlFs:context
【内容】体温表が記録された環境についての情報を表す親エレメント +
【省略】不可

===== M23.1.1. mmlFs:facility
【内容】体温表を記録した施設 +
【データ型】string +
【省略】不可 +
【属性】
[options="header"]
|===
|属性名|データ型|省略|使用テーブル|説明
|mmlFs:facilityCode|string|#REQUIRED| |
|mmlFs:facilityCodeId|string|#REQUIRED|MML0027|用いたコード体系の名称を記載
|===

===== M23.1.2. mmlFs:department
【内容】体温表を記録した部署 +
【データ型】string +
【省略】可 +
【属性】
[options="header"]
|===
|属性名|データ型|省略|使用テーブル|説明
|mmlFs:depCode|string|#IMPLIED|MML0028|
|mmlFs:depCodeId|string|#IMPLIED| | 		MML0028と入力
|===

===== M23.1.3. mmlFs:ward
【内容】体温表を記録した病棟・場所 +
【データ型】string +
【省略】可 +
【属性】
[options="header"]
|===
|属性名|データ型|省略|使用テーブル|説明
|mmlFs:wardCode|string|#IMPLIED|ユーザ指定|
|mmlFs:wardCodeId|string|#IMPLIED| |用いたテーブル名を入力
|===

===== M23.1.4. mmlFs:observer
【内容】体温表情報の観察者 +
【データ型】string +
【省略】可 +
【属性】
[options="header"]
|===
|属性名|データ型|省略|使用テーブル|説明
|mmlFs:obsCode|string|#IMPLIED|ユーザ指定|
|mmlFs:obsCodeId|string|#IMPLIED| |用いたテーブル名を入力
|===

===== M23.2. mmlVs:VitalSignModule
【内容】バイタルサイン情報 +
【省略】可 +
【繰り返し設定】繰り返しあり。測定された一連のバイタルサインの数だけ繰り返す。(例：ラウンド時に計測された収縮期血圧、拡張期血圧、脈拍、体温、SpO2）

===== M23.3. mmlFs:intake
【内容】水分や食事などの摂取状況に関する親エレメント +
【省略】可 +
【繰り返し設定】0回以上の繰り返しあり。

===== M23.3.1. mmlFs:intakeType
【内容】摂取した食べ物・飲み物の種類。例：朝食(主)、昼食（副）、水分、経管栄養食など。 +
【データ型】string +
【省略】不可。 +
【使用テーブル】mmlFs01

===== M23.3.2. mmlFs:intakeVolume
【内容】摂取した食べ物・飲み物の量。 +
【データ型】decimal +
【省略】省略可

===== M23.3.3. mmlFs:intakeUnit
【内容】摂取した食べ物・飲み物の単位。/10, ml, g, kcal, など +
【省略】省略可 +
【データ型】string +
【使用テーブル】mmlFs02

===== M23.3.4. mmlFs:intakePathway
【内容】摂取経路。経口摂取、経管、IVH管理など +
【データ型】string +
【省略】省略可

===== M23.3.5. mmlFs:intakeStartTime
【内容】摂取開始時間。観察を開始した時間を記録する。開始、終了の別なく記録をする場合にはこちらに時間を記入する。 +
【データ型】dateTime +
【省略】省略可

===== M23.3.6. mmlFs:intakeEndTime
【内容】摂取終了時間。 +
【データ型】dateTime +
【省略】省略可

===== M23.3.7. mmlFs:intakeMemo
【内容】摂取状況に関するコメント・メモ。 +
【データ型】string +
【省略】省略可

===== M23.4. mmlFs:bodilyOutput
【内容】体外に排泄されるものについて記録する親エレメント。尿、便以外にも胸水、腹水、体液、胆汁、その他の分泌物なども対処とする。 +
【省略】省略可 +
【繰り返し設定】0回以上繰り返しあり。

===== M23.4.1. mmlFs:boType
【内容】排泄物の種類。 +
【データ型】string +
【省略】不可 +
【使用テーブル】mmlFs03

===== M23.4.2. mmlFs:boVolume
【内容】排泄物の量。 +
【データ型】decimal +
【省略】省略可

===== M23.4.3. mmlFs:boUnit
【内容】排泄物の量の単位。 +
【データ型】string +
【省略】省略可 +
【使用テーブル】mmlFs04

===== M23.4.4. mmlFs:boStatus
【内容】排泄物の性状。軟便、下痢、混濁など。大量・中等量、少量など数値化できない場合にはここに記載する。 +
【データ型】string +
【省略】省略可

===== M23.4.5. mmlFs:boColor
【内容】排泄物の色調。黄色、茶褐色など。 +
【データ型】string +
【省略】省略可

===== M23.4.6. mmlFs:pathway
【内容】排泄経路、カテーテルやドレーン、ストマなど +
【データ型】string +
【省略】省略可

===== M23.4.7. mmlFs:boStartTime
【内容】排泄開始時間。観察を開始した時間を記録する。開始、終了の別なく記録をする場合にはこちらに時間を記入する。 +
【データ型】dateTime +
【省略】省略可

===== M23.4.8. mmlFs:boEndTime
【内容】排泄終了時間。 +
【データ型】dateTime +
【省略】省略可

===== M23.4.8. mmlFs:boMemo
【内容】排泄物に関するコメント、メモ。便秘3日目、出血は収束傾向など。 +
【データ型】string +
【省略】省略可

===== M23.4.9. mmlFs:boFrequency
【内容】一定時間内の排泄回数を表現する親エレメント。 +
【繰り返し】0回以上の繰り返しあり

===== M23.4.10. mmlFs:bofTimes
【内容】一定期間内に観察された排泄回数。 +
【データ型】decimal +
【省略】省略可

===== M23.4.10.1. mmlFs:bofPeriodStartTime
【内容】観察を開始した時間。 +
【データ型】dateTime +
【省略】省略可

===== M23.4.10.2. mmlFs:bofPeriodEndTime
【内容】観察を終了した時間。 +
【データ型】dateTime +
【省略】省略可

===== M23.4.10.3 mmlFs:bofMemo
【内容】数値化されない頻度表現。頻回、乏尿など。 +
【データ型】string +
【省略】省略可

===== M23.4.10.4. mmlFs:fsMemo
【内容】体温表コメント、メモ。その他の体温表に記載する内容。 +
【データ型】string +
【省略】省略可

:Author: Shinji KOBAYASHI
:Email: skoba@moss.gr.jp
:toc: right
:toclevels: 2
:pagenums:
:numberd:
:sectnums:
:imagesdir: ./figures
:linkcss:

=== 体温表モジュール
==== 目的と対象
日々の介護や看護で記録される体温表を記録するために使用される。

このモジュールにおいては、バイタルサインモジュールとあわせて、食事摂取量、排泄についての情報を扱っていく。想定されるユースケースは体温表に記載される各種情報である。

図に示すように、バイタルサインや摂食情報、排泄に関する情報は繰り返し記録される。

==== namespace宣言
このモジュールのnamespaceは以下のように宣言する。
[source, xml]
 xmlns:mmlFs="http://www.medxml.net/MML/v4/ContentModule/FlowSheet/1.0"

==== 文書ヘッダー情報 (docInfo) のモジュール個別仕様
===== docInfo
属性 contentModuleType に MML0005 テーブルより「flowsheet」を入力すること．

===== title
このモジュールは病棟あるいは介護施設などで日々記録される体温表を主なユースケースと考えている。したがって、レポートタイトルとしては「体温表」であることを前提とするが、病棟で慣用的に利用される「熱型表」「体温表」や「温度板」などが、タイトルとして使用されることも想定している。

属性の generationPurpose は，MML0007 テーブルより「flowsheet」 (体温表) と入力すること．

===== confirmDate
モジュール生成日であり，全体としての報告がなされた時刻を示す．

===== mmlCi:CreatorInfo
体温表モジュールでは、多職種にわたる複数の人間が観察した情報が一つの報告書に記載されることがある。最終的な記載者あるいは代表者が作成者情報として記録される。

.エレメント構造図
image::mmlfs.png[]

.エレメント一覧表
[options="header"]
|===
| |Elements|Attribute|Data types|Occurrence|TableId
|M23.|mmlFs:FlowSheetModule| | | |
|M23.1.|mmlFs:context| | | |
|M23.1.1.|mmlFs:facility| |string| |
| | |mmlFs:facilityCode|string|#REQUIRED|
| | |mmlFs:facilityCodeId|string|#REQUIRED|MML0027
|M23.1.2.|mmlFs:department| |string|?|
| | |mmlFs:depCode|string|#IMPLIED|MML0028
| | |mmlFs:depCodeId|string|#IMPLIED|
|M23.1.3.|mmlFs:ward| |string|?|
| | |mmlFs:wardCode|string|#IMPLIED|ユーザ指定
| | |mmlFs:wardCodeId|string|#IMPLIED|
|M23.1.4.|mmlFs:observer| |string|?|
| | |mmlFs:obsCode|string|#IMPLIED|ユーザ指定
| | |mmlFs:obsCodeId|string|#IMPLIED|
|M23.2.|mmlVs:VitalSignModule| | |*|
|M23.3.|mmlFs:intake| | |*|
|M23.3.1.|mmlFs:intakeType| |string| |mmlFs01
|M23.3.2.|mmlFs:intakeVolume| |decimal|?|
|M23.3.3.|mmlFs:intakeUnit| |string|?|mmlFs02
|M23.3.4.|mmlFs:intakePathway| |string|?|
|M23.3.5.|mmlFs:intakeStartTime| |dateTime|?|
|M23.3.6.|mmlFs:intakeEndTime| |dateTime|?|
|M23.3.7.|mmlFs:intakeMemo| |string|?|
|M23.4.|mmlFs:bodilyOutput| | |*|
|M23.4.1.|mmlFs:boType| |string| |mmlFs03
|M23.4.2.|mmlFs:boVolume| |decimal|?|
|M23.4.3.|mmlFs:boUnit| |string|?|mmlFs04
|M23.4.4.|mmlFs:boStatus| |string|?|
|M23.4.5.|mmlFs:boColor| |string|?|
|M23.4.6.|mmlFs:boPathway| |string|?|
|M23.4.7.|mmlFs:boStartTime| |dateTime|?|
|M23.4.8.|mmlFs:boEndTime| |dateTime|?|
|M23.4.9.|mmlFs:boMemo| |string|?|
|M23.4.10.|mmlFs:boFrequency| | |*|
|M23.4.10.1.|mmlFs:bofTimes| |decimal|?|
|M23.4.10.2.|mmlFs:bofPeriodStartTime| |dateTime|?|
|M23.4.10.3.|mmlFs:bofPeriodEndTime| |dateTime|?|
|M23.4.10.4.|mmlFs:bofMemo| |string|?|
|M23.5.|mmlFs:fsMemo| |string|?|
|===
Occurrenceなし：必ず1回出現，?： 0回もしくは1回出現，+： 1回以上出現，*： 0 回以上出現

#REQUIRED:必須属性，#IMPLIED:省略可能属性

==== エレメント解説
===== M23. mmlFs:FlowSheetModule
【内容】体温表モジュール

===== M23.1. mmlFs:context
【内容】体温表が記録された環境についての情報を表す親エレメント +
【省略】不可

===== M23.1.1. mmlFs:facility
【内容】体温表を記録した施設 +
【データ型】string +
【省略】不可 +
【属性】
[options="header"]
|===
|属性名|データ型|省略|使用テーブル|説明
|mmlFs:facilityCode|string|#REQUIRED| |
|mmlFs:facilityCodeId|string|#REQUIRED|MML0027|用いたコード体系の名称を記載
|===

===== M23.1.2. mmlFs:department
【内容】体温表を記録した部署 +
【データ型】string +
【省略】可 +
【属性】
[options="header"]
|===
|属性名|データ型|省略|使用テーブル|説明
|mmlFs:depCode|string|#IMPLIED|MML0028|
|mmlFs:depCodeId|string|#IMPLIED| | 		MML0028と入力
|===

===== M23.1.3. mmlFs:ward
【内容】体温表を記録した病棟・場所 +
【データ型】string +
【省略】可 +
【属性】
[options="header"]
|===
|属性名|データ型|省略|使用テーブル|説明
|mmlFs:wardCode|string|#IMPLIED|ユーザ指定|
|mmlFs:wardCodeId|string|#IMPLIED| |用いたテーブル名を入力
|===

===== M23.1.4. mmlFs:observer
【内容】体温表情報の観察者 +
【データ型】string +
【省略】可 +
【属性】
[options="header"]
|===
|属性名|データ型|省略|使用テーブル|説明
|mmlFs:obsCode|string|#IMPLIED|ユーザ指定|
|mmlFs:obsCodeId|string|#IMPLIED| |用いたテーブル名を入力
|===

===== M23.2. mmlVs:VitalSignModule
【内容】バイタルサイン情報 +
【省略】可 +
【繰り返し設定】繰り返しあり。測定された一連のバイタルサインの数だけ繰り返す。(例：ラウンド時に計測された収縮期血圧、拡張期血圧、脈拍、体温、SpO2）

===== M23.3. mmlFs:intake
【内容】水分や食事などの摂取状況に関する親エレメント +
【省略】可 +
【繰り返し設定】0回以上の繰り返しあり。

===== M23.3.1. mmlFs:intakeType
【内容】摂取した食べ物・飲み物の種類。例：朝食(主)、昼食（副）、水分、経管栄養食など。 +
【データ型】string +
【省略】不可。 +
【使用テーブル】mmlFs01

===== M23.3.2. mmlFs:intakeVolume
【内容】摂取した食べ物・飲み物の量。 +
【データ型】decimal +
【省略】省略可

===== M23.3.3. mmlFs:intakeUnit
【内容】摂取した食べ物・飲み物の単位。/10, ml, g, kcal, など +
【省略】省略可 +
【データ型】string +
【使用テーブル】mmlFs02

===== M23.3.4. mmlFs:intakePathway
【内容】摂取経路。経口摂取、経管、IVH管理など +
【データ型】string +
【省略】省略可

===== M23.3.5. mmlFs:intakeStartTime
【内容】摂取開始時間。観察を開始した時間を記録する。開始、終了の別なく記録をする場合にはこちらに時間を記入する。 +
【データ型】dateTime +
【省略】省略可

===== M23.3.6. mmlFs:intakeEndTime
【内容】摂取終了時間。 +
【データ型】dateTime +
【省略】省略可

===== M23.3.7. mmlFs:intakeMemo
【内容】摂取状況に関するコメント・メモ。 +
【データ型】string +
【省略】省略可

===== M23.4. mmlFs:bodilyOutput
【内容】体外に排泄されるものについて記録する親エレメント。尿、便以外にも胸水、腹水、体液、胆汁、その他の分泌物なども対処とする。 +
【省略】省略可 +
【繰り返し設定】0回以上繰り返しあり。

===== M23.4.1. mmlFs:boType
【内容】排泄物の種類。 +
【データ型】string +
【省略】不可 +
【使用テーブル】mmlFs03

===== M23.4.2. mmlFs:boVolume
【内容】排泄物の量。 +
【データ型】decimal +
【省略】省略可

===== M23.4.3. mmlFs:boUnit
【内容】排泄物の量の単位。 +
【データ型】string +
【省略】省略可 +
【使用テーブル】mmlFs04

===== M23.4.4. mmlFs:boStatus
【内容】排泄物の性状。軟便、下痢、混濁など。大量・中等量、少量など数値化できない場合にはここに記載する。 +
【データ型】string +
【省略】省略可

===== M23.4.5. mmlFs:boColor
【内容】排泄物の色調。黄色、茶褐色など。 +
【データ型】string +
【省略】省略可

===== M23.4.6. mmlFs:pathway
【内容】排泄経路、カテーテルやドレーン、ストマなど +
【データ型】string +
【省略】省略可

===== M23.4.7. mmlFs:boStartTime
【内容】排泄開始時間。観察を開始した時間を記録する。開始、終了の別なく記録をする場合にはこちらに時間を記入する。 +
【データ型】dateTime +
【省略】省略可

===== M23.4.8. mmlFs:boEndTime
【内容】排泄終了時間。 +
【データ型】dateTime +
【省略】省略可

===== M23.4.8. mmlFs:boMemo
【内容】排泄物に関するコメント、メモ。便秘3日目、出血は収束傾向など。 +
【データ型】string +
【省略】省略可

===== M23.4.9. mmlFs:boFrequency
【内容】一定時間内の排泄回数を表現する親エレメント。 +
【繰り返し】0回以上の繰り返しあり

===== M23.4.10. mmlFs:bofTimes
【内容】一定期間内に観察された排泄回数。 +
【データ型】decimal +
【省略】省略可

===== M23.4.10.1. mmlFs:bofPeriodStartTime
【内容】観察を開始した時間。 +
【データ型】dateTime +
【省略】省略可

===== M23.4.10.2. mmlFs:bofPeriodEndTime
【内容】観察を終了した時間。 +
【データ型】dateTime +
【省略】省略可

===== M23.4.10.3 mmlFs:bofMemo
【内容】数値化されない頻度表現。頻回、乏尿など。 +
【データ型】string +
【省略】省略可

===== M23.4.10.4. mmlFs:fsMemo
【内容】体温表コメント、メモ。その他の体温表に記載する内容。 +
【データ型】string +
【繰り返し】省略可