diff --git a/.github/workflows/automatic-doc-checks.yml b/.github/workflows/automatic-doc-checks.yml new file mode 100644 index 0000000000..479ebcbdc8 --- /dev/null +++ b/.github/workflows/automatic-doc-checks.yml @@ -0,0 +1,24 @@ +# +name: Automatic doc checks + +on: + push: + branches: [ main ] + pull_request: + paths: + - 'docs/**' # Only run on changes to the docs directory + + workflow_dispatch: + # Manual trigger + + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + documentation-checks: + uses: canonical/documentation-workflows/.github/workflows/documentation-checks.yaml@main + with: + working-directory: "docs" + fetch-depth: 0 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index cdf5a0e2e6..cdaae9244d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -14,7 +14,7 @@ on: - 'LICENSE' - '**.md' - .github/renovate.json5 - - '.github/workflows/sync_docs.yaml' + - 'docs/**' schedule: - cron: '53 0 * * *' # Daily at 00:53 UTC # Triggered on push to branch "main" by .github/workflows/release.yaml diff --git a/.github/workflows/lib-check.yaml b/.github/workflows/lib-check.yaml index 2da46ee6e7..e2816f83f8 100644 --- a/.github/workflows/lib-check.yaml +++ b/.github/workflows/lib-check.yaml @@ -14,6 +14,7 @@ on: - 'LICENSE' - '**.md' - 'renovate.json' + - 'docs/**' jobs: lib-check: diff --git a/.github/workflows/markdown-style-checks.yml b/.github/workflows/markdown-style-checks.yml new file mode 100644 index 0000000000..e0de019db3 --- /dev/null +++ b/.github/workflows/markdown-style-checks.yml @@ -0,0 +1,24 @@ +name: Markdown style checks + +on: + push: + branches: + - main + paths: + - 'docs/**' # Only run on changes to the docs directory + pull_request: + branches: + - '*' + paths: + - 'docs/**' # Only run on changes to the docs directory + +jobs: + markdown-lint: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: DavidAnson/markdownlint-cli2-action@v16 + with: + config: "docs/.sphinx/.markdownlint.json" diff --git a/.github/workflows/sync_docs.yaml b/.github/workflows/sync_docs.yaml deleted file mode 100644 index e22b702518..0000000000 --- a/.github/workflows/sync_docs.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2024 Canonical Ltd. -# See LICENSE file for licensing details. -name: Sync docs from Discourse - -on: - workflow_dispatch: - schedule: - - cron: '53 0 * * *' # Daily at 00:53 UTC - -jobs: - sync-docs: - name: Sync docs from Discourse - uses: canonical/data-platform-workflows/.github/workflows/sync_docs.yaml@v31.0.1 - with: - reviewers: a-velasco - permissions: - contents: write # Needed to push branch & tag - pull-requests: write # Needed to create PR diff --git a/.gitignore b/.gitignore index 75610a94ec..a63eb2144b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ build/ coverage.xml __pycache__/ *.py[cod] -requirements.txt +./requirements.txt requirements-last-build.txt # PyCharm project folder. diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000000..01d6b9f5b4 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,39 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the version of Python and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.11" + jobs: + post_checkout: + - git fetch --unshallow || true + # Cancel building pull requests when there aren't changed in the docs directory. + # If there are no changes (git diff exits with 0) we force the command to return with 183. + # This is a special exit code on Read the Docs that will cancel the build immediately. + # https://docs.readthedocs.io/en/stable/build-customization.html#cancel-build-based-on-a-condition + - | + if [ "$READTHEDOCS_VERSION_TYPE" = "external" ] && git diff --quiet origin/14/docs -- 'docs/' '.readthedocs.yaml'; + then + exit 183; + fi + +# Build documentation in the docs/ directory with Sphinx +sphinx: + builder: dirhtml + configuration: docs/conf.py + fail_on_warning: true + +# If using Sphinx, optionally build your docs in additional formats such as PDF +# formats: +# - pdf + +# Optionally declare the Python requirements required to build your docs +python: + install: + - requirements: docs/requirements.txt diff --git a/README.md b/README.md index e9fe08081d..fdac6d28a1 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,21 @@ # Charmed PostgreSQL K8s operator + [![CharmHub Badge](https://charmhub.io/postgresql-k8s/badge.svg)](https://charmhub.io/postgresql-k8s) [![Release](https://github.com/canonical/postgresql-k8s-operator/actions/workflows/release.yaml/badge.svg)](https://github.com/canonical/postgresql-k8s-operator/actions/workflows/release.yaml) [![Tests](https://github.com/canonical/postgresql-k8s-operator/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/canonical/postgresql-k8s-operator/actions/workflows/ci.yaml?query=branch%3Amain) [![codecov](https://codecov.io/gh/canonical/postgresql-k8s-operator/graph/badge.svg?token=KmBJqV1AM2)](https://codecov.io/gh/canonical/postgresql-k8s-operator) -## Description - -This repository contains a [Juju Charm](https://charmhub.io/postgresql-k8s) for deploying [PostgreSQL](https://www.postgresql.org/about/) on Kubernetes. +This repository contains a charmed operator for deploying [PostgreSQL](https://www.postgresql.org/about/) on Kubernetes via the [Juju orchestration engine](https://juju.is/). -To deploy on virtual machines, please use [Charmed PostgreSQL operator](https://charmhub.io/postgresql). +To learn more about how to deploy and operate Charmed PostgreSQL K8s, see the [official documentation](https://canonical-charmed-postgresql-k8s.readthedocs-hosted.com/). ## Usage -Bootstrap a Kubernetes (e.g. [Multipass-based MicroK8s](https://discourse.charmhub.io/t/charmed-environment-charm-dev-with-canonical-multipass/8886)) and create a new model using Juju 2.9+: +Bootstrap a Kubernetes (e.g. [Multipass-based MicroK8s](https://discourse.charmhub.io/t/charmed-environment-charm-dev-with-canonical-multipass/8886)) and create a new model using Juju 3.6+: ```shell juju add-model postgresql-k8s -juju deploy postgresql-k8s --channel 14 --trust +juju deploy postgresql-k8s --channel 14/stable --trust ``` **Note:** the `--trust` flag is required because the charm and Patroni need to create some K8s resources. @@ -62,7 +61,7 @@ Adding a relation is accomplished with `juju relate` (or `juju integrate` for Ju ```shell # Deploy Charmed PostgreSQL cluster with 3 nodes -juju deploy postgresql-k8s -n 3 --trust --channel 14 +juju deploy postgresql-k8s --channel 14/stable -n 3 --trust --channel 14 # Deploy the relevant application charms juju deploy mycharm @@ -87,7 +86,7 @@ juju status --relations This charm supports legacy interface `pgsql` from the previous [PostgreSQL charm](https://launchpad.net/postgresql-charm): ```shell -juju deploy postgresql-k8s --trust --channel 14 +juju deploy postgresql-k8s --channel 14/stable --trust juju deploy finos-waltz-k8s --channel edge juju relate postgresql-k8s:db finos-waltz-k8s ``` diff --git a/docs/.custom_wordlist.txt b/docs/.custom_wordlist.txt new file mode 100644 index 0000000000..52d5f8c616 --- /dev/null +++ b/docs/.custom_wordlist.txt @@ -0,0 +1,40 @@ +# Leave a blank line at the end of this file to support concatenation +backend +backends +Charmcraft +cjk +cryptographically +dvipng +fonts +freefont +github +GPG +gyre +https +Intersphinx +lang +LaTeX +latexmk +Multipass +otf +plantuml +PNG +Pygments +QEMU +Rockcraft +rst +SVG +tex +texlive +TOC +toctree +txt +uncommenting +utils +VMs +WCAG +whitespace +whitespaces +wordlist +xetex +xindy diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000000..aad78f1f7c --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,26 @@ +# Environment +*env*/ +.sphinx/venv/ + +# Sphinx +.sphinx/warnings.txt +.sphinx/.wordlist.dic +.sphinx/.doctrees/ +.sphinx/update/ +.sphinx/node_modules/ + +# Vale +.sphinx/styles/* +.sphinx/vale.ini + +# Build outputs +_build + +# Node.js +package*.json + +# Unrelated cache and config files +.DS_Store +__pycache__ +.idea/ +.vscode/ diff --git a/docs/.sphinx/.markdownlint.json b/docs/.sphinx/.markdownlint.json new file mode 100644 index 0000000000..536f9ea929 --- /dev/null +++ b/docs/.sphinx/.markdownlint.json @@ -0,0 +1,21 @@ +{ + "default": false, + "MD003": { + "style": "atx" + }, + "MD014": true, + "MD018": true, + "MD022": true, + "MD023": true, + "MD026": { + "punctuation": ".,;。,;" + }, + "MD031": { + "list_items": false + }, + "MD032": true, + "MD035": true, + "MD042": true, + "MD045": true, + "MD052": true +} \ No newline at end of file diff --git a/docs/.sphinx/.pre-commit-config.yaml b/docs/.sphinx/.pre-commit-config.yaml new file mode 100644 index 0000000000..07e0b48cbd --- /dev/null +++ b/docs/.sphinx/.pre-commit-config.yaml @@ -0,0 +1,23 @@ +repos: + - repo: local + hooks: + - id: make-spelling + name: Run make spelling + entry: make -C docs spelling + language: system + pass_filenames: false + files: ^docs/.*\.(rst|md|txt)$ + + - id: make-linkcheck + name: Run make linkcheck + entry: make -C docs linkcheck + language: system + pass_filenames: false + files: ^docs/.*\.(rst|md|txt)$ + + - id: make-woke + name: Run make woke + entry: make -C docs woke + language: system + pass_filenames: false + files: ^docs/.*\.(rst|md|txt)$ diff --git a/docs/.sphinx/.wordlist.txt b/docs/.sphinx/.wordlist.txt new file mode 100644 index 0000000000..fd1f10102e --- /dev/null +++ b/docs/.sphinx/.wordlist.txt @@ -0,0 +1,331 @@ +ACME +ACME's +addons +AGPLv +API +APIs +balancer +Charmhub +CLI +DCO +Diátaxis +Dqlite +dropdown +EBS +EKS +enablement +favicon +Furo +Git +GitHub +Grafana +IAM +installable +JSON +Juju +Kubeflow +Kubernetes +Launchpad +linter +LTS +LXD +Makefile +Makefiles +Matrix +Mattermost +MicroCeph +MicroCloud +MicroOVN +MyST +namespace +namespaces +NodePort +Numbat +observability +OEM +OLM +Permalink +pre +Quickstart +ReadMe +reST +reStructuredText +roadmap +RTD +subdirectories +subfolders +subtree +TODO +Ubuntu +UI +UUID +VM +webhook +YAML + +AAM +AAR +AArch +ABI +ADB +ADSys +AKS +AMC +AMS +ANAIS +APK +APM +ARMv +ARR +ASIC +AZ +BAU +BOM +BTS +BZR +CAC +CBR +CDK +CDN +CISC +CLA +CMP +CNI +COS +COTS +CPC +CPQ +CPT +CR +CRD +CRI +CSB +CSI +CTR +CVE +DBR +DEP +DHCP +DKMS +DMB +DNS +DPU +DSA +DSE +EE +EFI +EoL +EoS +EPMO +ESM +FCE +FFE +FIPS +FOSS +FPGA +FTBFS +FTI +FUSE +GKE +GPGPU +GPL +GSI +GTM +HA +HAP +HPC +HWE +IC +IHV +IOV +IPMI +IPU +IRCC +iSCSI +ISM +ISR +ISV +ITP +JAAS +KSPP +LTV +MAAS +MDF +MDL +MEC +MLflow +MOTU +MPA +MQL +MRE +MSRP +NATS +NFS +NIC +NIH +NIST +NOC +NOS +NPOASR +NPV +NRE +NUMA +NVIU +NVMe +OBSD +OCI +OCL +OCTO +ODM +OSD +OSS +OVA +OVAL +OVN +OVS +P4 +PCB +PCF +PCKN +PCRE +PKCS +PKS +PMO +POSIX +PPA +PS5 +PXE +RACI +RADOS +RAG +RBAC +RDMA +RTOS +SDK +SDR +SDS +SEG +SFDC +SIP +SKU +SLA +SOW +SQL +SR +SRU +TAM +TCS +TFTP +TLS +TPM +TUI +UCA +UCT +UDS +UIFe +URI +UX +VCS +VNFD +WSL +ZFS + +Anbox +Ansible +Appium +Backports +Ceph +Changelog +Charmcraft +CoC +CoF +Containerd +Coturn +Cryptographic +Devel +Endian +Endianness +Fluentd +GraphQL +HAProxy +HAcluster +Imagecraft +Infiniband +Influxdb +Istio +Kata +Keepalived +KernOS +KernelFactory +Keyring +Keyserver +Kibana +Knative +LXC +Laravel +Libvirt +Linkerd +LinuxONE +Livepatch +Mesos +Metallb +MicroK +MicroStack +Mojo +Multipass +Nagios +NetApp +Netplan +Nginx +OpenSSL +OpenSearch +OpenStack +Openshift +PgBouncer +QEMU +RabbitMQ +Rasterization +Rebase +RegEx +RoM +RoP +RoQA +RoSRM +RoST +Rockcraft +SQLair +Scrcpy +Snapcraft +Snapd +Splunk +Subnet +Superdistro +Superset +Telegraf +Terraform +Testflinger +Thruk +Tigera +TrilioVault +TripleO +Vue +WebRTC +WoU +amd +armhf +autopkgtest +cURL +containeragent +dqlite +dsc +init +jQuery +juju +jujuc +jujud +ppc +riscv +snapcrafting +subcluster +swrast +zSystems diff --git a/docs/.sphinx/get_vale_conf.py b/docs/.sphinx/get_vale_conf.py new file mode 100644 index 0000000000..46f57d8943 --- /dev/null +++ b/docs/.sphinx/get_vale_conf.py @@ -0,0 +1,151 @@ +#! /usr/bin/env python + +import os +import shutil +import subprocess +import tempfile +import sys +import logging +import argparse + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' +) + +SPHINX_DIR = os.path.join(os.getcwd(), ".sphinx") + +GITHUB_REPO = "canonical/praecepta" +GITHUB_CLONE_URL = f"https://github.com/{GITHUB_REPO}.git" + +# Source paths to copy from repo +VALE_FILE_LIST = [ + "styles/Canonical", + "styles/config/vocabularies/Canonical", + "styles/config/dictionaries", + "vale.ini" +] + +def clone_repo_and_copy_paths(file_source_dest, overwrite=False): + """ + Clone the repository to a temporary directory and copy required files + + Args: + file_source_dest: dictionary of file paths to copy from the repository, + and their destination paths + overwrite: boolean flag to overwrite existing files in the destination + + Returns: + bool: True if all files were copied successfully, False otherwise + """ + + if not file_source_dest: + logging.error("No files to copy") + return False + + # Create temporary directory on disk for cloning + temp_dir = tempfile.mkdtemp() + logging.info("Cloning repository <%s> to temporary directory: %s", GITHUB_REPO, temp_dir) + clone_cmd = ["git", "clone", "--depth", "1", GITHUB_CLONE_URL, temp_dir] + + try: + result = subprocess.run( + clone_cmd, + capture_output=True, + text=True, + check=True + ) + logging.debug("Git clone output: %s", result.stdout) + except subprocess.CalledProcessError as e: + logging.error("Git clone failed: %s", e.stderr) + return False + + # Copy files from the cloned repository to the destination paths + is_copy_success = True + for source, dest in file_source_dest.items(): + source_path = os.path.join(temp_dir, source) + + if not os.path.exists(source_path): + is_copy_success = False + logging.error("Source path not found: %s", source_path) + continue + + if not copy_files_to_path(source_path, dest, overwrite): + is_copy_success = False + logging.error("Failed to copy %s to %s", source_path, dest) + + # Clean up temporary directory + logging.info("Cleaning up temporary directory: %s", temp_dir) + shutil.rmtree(temp_dir) + + return is_copy_success + +def copy_files_to_path(source_path, dest_path, overwrite=False): + """ + Copy a file or directory from source to destination + + Args: + source_path: Path to the source file or directory + dest_path: Path to the destination + overwrite: Boolean flag to overwrite existing files in the destination + + Returns: + bool: True if copy was successful, False otherwise + """ + # Skip if source file doesn't exist + if not os.path.exists(source_path): + logging.warning("Source path not found: %s", source_path) + return False + + logging.info("Copying %s to %s", source_path, dest_path) + # Handle existing files + if os.path.exists(dest_path): + if overwrite: + logging.info(" Destination exists, overwriting: %s", dest_path) + if os.path.isdir(dest_path): + shutil.rmtree(dest_path) + else: + os.remove(dest_path) + else: + logging.info(" Destination exists, skip copying (use overwrite=True to replace): %s", + dest_path) + return True # Skip copying + + # Copy the source to destination + try: + if os.path.isdir(source_path): + # entire directory + shutil.copytree(source_path, dest_path) + else: + # individual files + shutil.copy2(source_path, dest_path) + return True + except (shutil.Error, OSError) as e: + logging.error("Copy failed: %s", e) + return False + +def parse_arguments(): + parser = argparse.ArgumentParser(description="Download Vale configuration files") + parser.add_argument("--no-overwrite", action="store_true", help="Don't overwrite existing files") + return parser.parse_args() + +def main(): + # Define local directory paths + vale_files_dict = {file: os.path.join(SPHINX_DIR, file) for file in VALE_FILE_LIST} + + # Parse command line arguments, default to overwrite_enabled = True + overwrite_enabled = not parse_arguments().no_overwrite + + # Download into /tmp through git clone + if not clone_repo_and_copy_paths(vale_files_dict, overwrite=overwrite_enabled): + logging.error("Failed to download files from repository") + return 1 + + logging.info("Download complete") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) # Keep return code diff --git a/docs/.sphinx/metrics/build_metrics.sh b/docs/.sphinx/metrics/build_metrics.sh new file mode 100755 index 0000000000..bd1ff1cb4c --- /dev/null +++ b/docs/.sphinx/metrics/build_metrics.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# shellcheck disable=all + +links=0 +images=0 + +# count number of links +links=$(find . -type d -path './.sphinx' -prune -o -name '*.html' -exec cat {} + | grep -o " str: + """Get SHA of local files""" + logging.debug(f"Getting hash of {os.path.basename(file)}") + return subprocess.check_output(["git", "hash-object", file]).decode("ascii").strip() + + +# Examines local files +def get_local_files_and_paths(): + """Identify '.sphinx' local files and paths""" + logging.debug("Checking local files and paths") + try: + files = [] + paths = [] + patterns = [".*", "**.*", "metrics/**.*"] + files, paths = [], [] + + for pattern in patterns: + for file in glob.iglob(os.path.join(SPHINX_DIR, pattern), recursive=True): + files.append(os.path.basename(file)) + paths.append(file) + return files, paths + except Exception as e: + logging.debug(e) + raise RuntimeError("get_local_files_and_paths()") from e + + +# General API query with timeout and RequestException +def query_api(url): + """Query an API with a globally set timeout""" + logging.debug(f"Querying {url}") + try: + r = requests.get(url, timeout=TIMEOUT) + return r + except RequestException as e: + raise RuntimeError(f"Failed query_api(): {url}") from e + + +# General file download function +def download_file(url, output_path): + """Download a file to a specified path""" + logging.debug(f"Downloading {os.path.basename(output_path)}") + try: + os.makedirs(os.path.dirname(output_path), exist_ok=True) + with open(output_path, "wb") as file: + file.write(query_api(url).content) + except Exception as e: + logging.debug(e) + raise RuntimeError(f"Failed download_file(): {url}") from e + + +if __name__ == "__main__": + sys.exit(main()) # Keep return code diff --git a/docs/.sphinx/version b/docs/.sphinx/version new file mode 100644 index 0000000000..6d7de6e6ab --- /dev/null +++ b/docs/.sphinx/version @@ -0,0 +1 @@ +1.0.2 diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000000..a6553b8e19 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,196 @@ +# Minimal makefile for Sphinx documentation +# +# Add your customisation to `Makefile` instead. + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXDIR = .sphinx +SPHINXOPTS ?= -c . -d $(SPHINXDIR)/.doctrees -j auto +SPHINXBUILD ?= $(VENVDIR)/bin/sphinx-build +SOURCEDIR = . +BUILDDIR = _build +VENVDIR = $(SPHINXDIR)/venv +PA11Y = $(SPHINXDIR)/node_modules/pa11y/bin/pa11y.js --config $(SPHINXDIR)/pa11y.json +VENV = $(VENVDIR)/bin/activate +TARGET = * +ALLFILES = *.rst **/*.rst +METRICSDIR = $(SOURCEDIR)/.sphinx/metrics +REQPDFPACKS = latexmk fonts-freefont-otf texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended texlive-font-utils texlive-lang-cjk texlive-xetex plantuml xindy tex-gyre dvipng +CONFIRM_SUDO ?= N +VALE_CONFIG = $(SPHINXDIR)/vale.ini +SPHINX_HOST ?= 127.0.0.1 +SPHINX_PORT ?= 8000 + +# Put it first so that "make" without argument is like "make help". +help: + @echo + @echo "-------------------------------------------------------------" + @echo "* watch, build and serve the documentation: make run" + @echo "* only build: make html" + @echo "* only serve: make serve" + @echo "* clean built doc files: make clean-doc" + @echo "* clean full environment: make clean" + @echo "* check links: make linkcheck" + @echo "* check spelling: make spelling" + @echo "* check spelling (without building again): make spellcheck" + @echo "* check inclusive language: make woke" + @echo "* check accessibility: make pa11y" + @echo "* check style guide compliance: make vale" + @echo "* check style guide compliance on target: make vale TARGET=*" + @echo "* check metrics for documentation: make allmetrics" + @echo "* other possible targets: make " + @echo "-------------------------------------------------------------" + @echo + +.PHONY: full-help spellcheck-install pa11y-install install run html \ + epub serve clean clean-doc spelling spellcheck linkcheck woke \ + allmetrics pa11y pdf-prep-force pdf-prep pdf vale-install vale \ + update + +full-help: $(VENVDIR) + @. $(VENV); $(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + @echo "\n\033[1;31mNOTE: This help texts shows unsupported targets!\033[0m" + @echo "Run 'make help' to see supported targets." + +# If requirements are updated, venv should be rebuilt and timestamped. +$(VENVDIR): + python3 -c "import venv" || \ + (echo "You must install python3-venv before you can build the documentation."; exit 1) + @echo "... setting up virtualenv" + python3 -m venv $(VENVDIR) + . $(VENV); pip install $(PIPOPTS) --require-virtualenv \ + --upgrade -r requirements.txt \ + --log $(VENVDIR)/pip_install.log + @test ! -f $(VENVDIR)/pip_list.txt || \ + mv $(VENVDIR)/pip_list.txt $(VENVDIR)/pip_list.txt.bak + @. $(VENV); pip list --local --format=freeze > $(VENVDIR)/pip_list.txt + @touch $(VENVDIR) + +spellcheck-install: + @type aspell >/dev/null 2>&1 || \ + { \ + echo "Installing system-wide \"aspell\" packages..."; \ + confirm_sudo=$(CONFIRM_SUDO); \ + if [ "$$confirm_sudo" != "y" ] && [ "$$confirm_sudo" != "Y" ]; then \ + read -p "This requires sudo privileges. Proceed? [y/N]: " confirm_sudo; \ + fi; \ + if [ "$$confirm_sudo" = "y" ] || [ "$$confirm_sudo" = "Y" ]; then \ + sudo apt-get install aspell aspell-en; \ + else \ + echo "Installation cancelled."; \ + fi \ + } + +pa11y-install: + @type $(PA11Y) >/dev/null 2>&1 || { \ + echo "Installing \"pa11y\" from npm..."; echo; \ + mkdir -p $(SPHINXDIR)/node_modules/ ; \ + npm install --prefix $(SPHINXDIR) pa11y; \ + } + +install: $(VENVDIR) + +run: install + . $(VENV); $(VENVDIR)/bin/sphinx-autobuild -b dirhtml --host $(SPHINX_HOST) --port $(SPHINX_PORT) "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) + +# Doesn't depend on $(BUILDDIR) to rebuild properly at every run. +html: install + . $(VENV); $(SPHINXBUILD) -W --keep-going -b dirhtml "$(SOURCEDIR)" "$(BUILDDIR)" -w $(SPHINXDIR)/warnings.txt $(SPHINXOPTS) + +epub: install + . $(VENV); $(SPHINXBUILD) -b epub "$(SOURCEDIR)" "$(BUILDDIR)" -w $(SPHINXDIR)/warnings.txt $(SPHINXOPTS) + +serve: html + cd "$(BUILDDIR)"; python3 -m http.server --bind 127.0.0.1 8000 + +clean: clean-doc + @test ! -e "$(VENVDIR)" -o -d "$(VENVDIR)" -a "$(abspath $(VENVDIR))" != "$(VENVDIR)" + rm -rf $(VENVDIR) + rm -rf $(SPHINXDIR)/node_modules/ + rm -rf $(SPHINXDIR)/styles + rm -rf $(VALE_CONFIG) + +clean-doc: + git clean -fx "$(BUILDDIR)" + rm -rf $(SPHINXDIR)/.doctrees + +spellcheck: spellcheck-install + . $(VENV) ; python3 -m pyspelling -c $(SPHINXDIR)/spellingcheck.yaml -j $(shell nproc) + +spelling: html spellcheck + +linkcheck: install + . $(VENV) ; $(SPHINXBUILD) -b linkcheck "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) || { grep --color -F "[broken]" "$(BUILDDIR)/output.txt"; exit 1; } + exit 0 + +pa11y: pa11y-install html + find $(BUILDDIR) -name *.html -print0 | xargs -n 1 -0 $(PA11Y) + +vale-install: install + @. $(VENV); test -d $(SPHINXDIR)/venv/lib/python*/site-packages/vale || pip install rst2html vale + @. $(VENV); test -f $(VALE_CONFIG) || python3 $(SPHINXDIR)/get_vale_conf.py + @echo '.Name=="Canonical.400-Enforce-inclusive-terms"' > $(SPHINXDIR)/styles/woke.filter + @echo '.Level=="error" and .Name!="Canonical.500-Repeated-words" and .Name!="Canonical.000-US-spellcheck"' > $(SPHINXDIR)/styles/error.filter + @echo '.Name=="Canonical.000-US-spellcheck"' > $(SPHINXDIR)/styles/spelling.filter + @. $(VENV); find $(SPHINXDIR)/venv/lib/python*/site-packages/vale/vale_bin -size 195c -exec vale --version \; + +woke: vale-install + @cat $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept.txt > $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept_backup.txt + @cat $(SPHINXDIR)/.wordlist.txt $(SOURCEDIR)/.custom_wordlist.txt >> $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept.txt + @echo "Running Vale acceptable term check against $(TARGET). To change target set TARGET= with make command" + @. $(VENV); vale --config="$(VALE_CONFIG)" --filter='$(SPHINXDIR)/styles/woke.filter' --glob='*.{md,rst}' $(TARGET) + @cat $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept_backup.txt > $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept.txt && rm $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept_backup.txt + +vale: vale-install + @cat $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept.txt > $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept_backup.txt + @cat $(SPHINXDIR)/.wordlist.txt $(SOURCEDIR)/.custom_wordlist.txt >> $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept.txt + @echo "Running Vale against $(TARGET). To change target set TARGET= with make command" + @. $(VENV); vale --config="$(VALE_CONFIG)" --filter='$(SPHINXDIR)/styles/error.filter' --glob='*.{md,rst}' $(TARGET) + @cat $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept_backup.txt > $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept.txt && rm $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept_backup.txt + +vale-spelling: vale-install + @cat $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept.txt > $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept_backup.txt + @cat $(SPHINXDIR)/.wordlist.txt $(SOURCEDIR)/.custom_wordlist.txt >> $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept.txt + @echo "Running Vale against $(TARGET). To change target set TARGET= with make command" + @. $(VENV); vale --config="$(VALE_CONFIG)" --filter='$(SPHINXDIR)/styles/spelling.filter' --glob='*.{md,rst}' $(TARGET) + @cat $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept_backup.txt > $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept.txt && rm $(SPHINXDIR)/styles/config/vocabularies/Canonical/accept_backup.txt + +pdf-prep: install + @for packageName in $(REQPDFPACKS); do (dpkg-query -W -f='$${Status}' $$packageName 2>/dev/null | \ + grep -c "ok installed" >/dev/null && echo "Package $$packageName is installed") && continue || \ + (echo; echo "PDF generation requires the installation of the following packages: $(REQPDFPACKS)" && \ + echo "" && echo "Run 'sudo make pdf-prep-force' to install these packages" && echo "" && echo \ + "Please be aware these packages will be installed to your system") && exit 1 ; done + +pdf-prep-force: + apt-get update + apt-get upgrade -y + apt-get install --no-install-recommends -y $(REQPDFPACKS) \ + +pdf: pdf-prep + @. $(VENV); sphinx-build -M latexpdf "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) + @rm ./$(BUILDDIR)/latex/front-page-light.pdf || true + @rm ./$(BUILDDIR)/latex/normal-page-footer.pdf || true + @find ./$(BUILDDIR)/latex -name "*.pdf" -exec mv -t ./$(BUILDDIR) {} + + @rm -r $(BUILDDIR)/latex + @echo + @echo "Output can be found in ./$(BUILDDIR)" + @echo + +allmetrics: html + @echo "Recording documentation metrics..." + @echo "Checking for existence of vale..." + . $(VENV) + @. $(VENV); test -d $(SPHINXDIR)/venv/lib/python*/site-packages/vale || pip install vale + @. $(VENV); test -f $(VALE_CONFIG) || python3 $(SPHINXDIR)/get_vale_conf.py + @. $(VENV); find $(SPHINXDIR)/venv/lib/python*/site-packages/vale/vale_bin -size 195c -exec vale --config "$(VALE_CONFIG)" $(TARGET) > /dev/null \; + @eval '$(METRICSDIR)/source_metrics.sh $(PWD)' + @eval '$(METRICSDIR)/build_metrics.sh $(PWD) $(METRICSDIR)' + +update: install + @. $(VENV); .sphinx/update_sp.py + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: + . $(VENV); $(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000000..01d22f0eb2 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,337 @@ +import datetime +import ast +import os +import yaml + +# Configuration for the Sphinx documentation builder. +# All configuration specific to your project should be done in this file. +# +# If you're new to Sphinx and don't want any advanced or custom features, +# just go through the items marked 'TODO'. +# +# A complete list of built-in Sphinx configuration values: +# https://www.sphinx-doc.org/en/master/usage/configuration.html +# +# Our starter pack uses the custom Canonical Sphinx extension +# to keep all documentation based on it consistent and on brand: +# https://github.com/canonical/canonical-sphinx + + +####################### +# Project information # +####################### + +# Project name + +project = "Charmed PostgreSQL K8s" +author = "Canonical Ltd." + + +# Sidebar documentation title; best kept reasonably short +# +# TODO: To include a version number, add it here (hardcoded or automated). +# +# TODO: To disable the title, set to an empty string. + +html_title = project + " 14 documentation" + + +# Copyright string; shown at the bottom of the page +# +# Now, the starter pack uses CC-BY-SA as the license +# and the current year as the copyright year. +# +# TODO: If your docs need another license, specify it instead of 'CC-BY-SA'. +# +# TODO: If your documentation is a part of the code repository of your project, +# it inherits the code license instead; specify it instead of 'CC-BY-SA'. +# +# NOTE: For static works, it is common to provide the first publication year. +# Another option is to provide both the first year of publication +# and the current year, especially for docs that frequently change, +# e.g. 2022–2023 (note the en-dash). +# +# A way to check a repo's creation date is to get a classic GitHub token +# with 'repo' permissions; see https://github.com/settings/tokens +# Next, use 'curl' and 'jq' to extract the date from the API's output: +# +# curl -H 'Authorization: token ' \ +# -H 'Accept: application/vnd.github.v3.raw' \ +# https://api.github.com/repos/canonical/ | jq '.created_at' + +copyright = "%s CC-BY-SA, %s" % (datetime.date.today().year, author) + + +# Documentation website URL +# +# TODO: Update with the official URL of your docs or leave empty if unsure. +# +# NOTE: The Open Graph Protocol (OGP) enhances page display in a social graph +# and is used by social media platforms; see https://ogp.me/ + +ogp_site_url = "https://charmed-postgresql-k8s.readthedocs-hosted.com/" + + +# Preview name of the documentation website +# +# TODO: To use a different name for the project in previews, update as needed. + +ogp_site_name = project + + +# Preview image URL +# +# TODO: To customise the preview image, update as needed. + +ogp_image = "https://assets.ubuntu.com/v1/253da317-image-document-ubuntudocs.svg" + + +# Product favicon; shown in bookmarks, browser tabs, etc. + +# TODO: To customise the favicon, uncomment and update as needed. + +# html_favicon = '.sphinx/_static/favicon.png' + + +# Dictionary of values to pass into the Sphinx context for all pages: +# https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-html_context + +html_context = { + # Product page URL; can be different from product docs URL + # + # TODO: Change to your product website URL, + # dropping the 'https://' prefix, e.g. 'ubuntu.com/lxd'. + # + # TODO: If there's no such website, + # remove the {{ product_page }} link from the page header template + # (usually .sphinx/_templates/header.html; also, see README.rst). + "product_page": "canonical.com/data/postgresql", + + # Product tag image; the orange part of your logo, shown in the page header + # + # TODO: To add a tag image, uncomment and update as needed. + # 'product_tag': '_static/tag.png', + + # Your Discourse instance URL + # + # TODO: Change to your Discourse instance URL or leave empty. + # + # NOTE: If set, adding ':discourse: 123' to an .rst file + # will add a link to Discourse topic 123 at the bottom of the page. + "discourse": "https://discourse.charmhub.io", + + # Your Mattermost channel URL + # + # TODO: Change to your Mattermost channel URL or leave empty. + "mattermost": "", + + # Your Matrix channel URL + # + "matrix": "https://matrix.to/#/#charmhub-data-platform:ubuntu.com", + + # Your documentation GitHub repository URL + # + # TODO: Change to your documentation GitHub repository URL or leave empty. + # + # NOTE: If set, links for viewing the documentation source files + # and creating GitHub issues are added at the bottom of each page. + "github_url": "https://github.com/canonical/postgresql-k8s-operator", + + # Docs branch in the repo; used in links for viewing the source files + # TODO: Update when default branch changes to 14 or 16 + 'repo_default_branch': 'main', + + # Docs location in the repo; used in links for viewing the source files + "repo_folder": "/docs/", + + # Enable or disable the Previous / Next buttons at the bottom of pages + # Valid options: none, prev, next, both + "sequential_nav": "none", + + # Enable listing contributors on individual pages, set to True + "display_contributors": True, + + # Required for feedback button + 'github_issues': 'enabled', +} + +# TODO: To enable the edit button on pages, uncomment and change the link to a +# public repository on GitHub or Launchpad. Any of the following link domains +# are accepted: +# - https://github.com/example-org/example" +# - https://launchpad.net/example +# - https://git.launchpad.net/example +# +html_theme_options = { +'source_edit_link': 'https://github.com/canonical/postgresql-k8s-operator', +} + +# Project slug; see https://meta.discourse.org/t/what-is-category-slug/87897 +# +# TODO: If your documentation is hosted on https://docs.ubuntu.com/, +# uncomment and update as needed. + +# slug = '' + + +# Template and asset locations + +#html_static_path = ["_static"] +#templates_path = ["_templates"] + + +############# +# Redirects # +############# + +# To set up redirects: https://documatt.gitlab.io/sphinx-reredirects/usage.html +# For example: 'explanation/old-name.html': '../how-to/prettify.html', + +# To set up redirects in the Read the Docs project dashboard: +# https://docs.readthedocs.io/en/stable/guides/redirects.html + +# NOTE: If undefined, set to None, or empty, +# the sphinx_reredirects extension will be disabled. + +redirects = {} + + +########################### +# Link checker exceptions # +########################### + +# A regex list of URLs that are ignored by 'make linkcheck' +# +# TODO: Remove or adjust the ACME entry after you update the contributing guide + +linkcheck_ignore = [ + "http://127.0.0.1:8000", + "https://github.com/canonical/ACME/*", + "https://matrix.to/*" + ] + +# A regex list of URLs where anchors are ignored by 'make linkcheck' + +linkcheck_anchors_ignore_for_url = [ + r"https://github\.com/.*", + r"https://canonical-juju.readthedocs-hosted.com/en/latest/*" + ] + +# give linkcheck multiple tries on failure +# linkcheck_timeout = 30 +linkcheck_retries = 3 + +######################## +# Configuration extras # +######################## + +# Custom MyST syntax extensions; see +# https://myst-parser.readthedocs.io/en/latest/syntax/optional.html +# +# NOTE: By default, the following MyST extensions are enabled: +# substitution, deflist, linkify + +myst_enable_extensions = set() + +myst_heading_anchors = 3 + +# Custom Sphinx extensions; see +# https://www.sphinx-doc.org/en/master/usage/extensions/index.html + +# NOTE: The canonical_sphinx extension is required for the starter pack. +# It automatically enables the following extensions: +# - custom-rst-roles +# - myst_parser +# - notfound.extension +# - related-links +# - sphinx_copybutton +# - sphinx_design +# - sphinx_reredirects +# - sphinx_tabs.tabs +# - sphinxcontrib.jquery +# - sphinxext.opengraph +# - terminal-output +# - youtube-links + +extensions = [ + "canonical_sphinx", + "sphinxcontrib.cairosvgconverter", + "sphinx_last_updated_by_git", + "sphinx.ext.intersphinx", + "sphinxcontrib.mermaid" +] + +# Excludes files or directories from processing + +exclude_patterns = [ + "doc-cheat-sheet*", +] + +# Adds custom CSS files, located under 'html_static_path' + +# html_css_files = [] + + +# Adds custom JavaScript files, located under 'html_static_path' + +# html_js_files = [] + + +# Specifies a reST snippet to be appended to each .rst file + +rst_epilog = """ +.. include:: /reuse/links.txt +.. include:: /reuse/substitutions.txt +""" + +# Feedback button at the top; enabled by default +# +# TODO: To disable the button, uncomment this. + +# disable_feedback_button = True + + +# Your manpage URL +# +# TODO: To enable manpage links, uncomment and replace {codename} with required +# release, preferably an LTS release (e.g. noble). Do *not* substitute +# {section} or {page}; these will be replaced by sphinx at build time +# +# NOTE: If set, adding ':manpage:' to an .rst file +# adds a link to the corresponding man section at the bottom of the page. + +# manpages_url = 'https://manpages.ubuntu.com/manpages/{codename}/en/' + \ +# 'man{section}/{page}.{section}.html' + + +# Specifies a reST snippet to be prepended to each .rst file +# This defines a :center: role that centers table cell content. +# This defines a :h2: role that styles content for use with PDF generation. + +rst_prolog = """ +.. role:: center + :class: align-center +.. role:: h2 + :class: hclass2 +.. role:: woke-ignore + :class: woke-ignore +.. role:: vale-ignore + :class: vale-ignore +""" + +# Workaround for https://github.com/canonical/canonical-sphinx/issues/34 + +if "discourse_prefix" not in html_context and "discourse" in html_context: + html_context["discourse_prefix"] = html_context["discourse"] + "/t/" + +# Workaround for substitutions.yaml + +if os.path.exists('./reuse/substitutions.yaml'): + with open('./reuse/substitutions.yaml', 'r') as fd: + myst_substitutions = yaml.safe_load(fd.read()) + +# Add configuration for intersphinx mapping + +# intersphinx_mapping = { +# '14': ('https://canonical-charmed-postgresql.readthedocs-hosted.com/en/14/', None) +# } diff --git a/docs/explanation.md b/docs/explanation.md deleted file mode 100644 index 74ea9e3f42..0000000000 --- a/docs/explanation.md +++ /dev/null @@ -1,39 +0,0 @@ -# Explanation - -This section contains pages with more detailed explanations that provide additional context about some of the key concepts behind the PostgreSQL charm: - -## Core concepts and design -* [Architecture] -* [Interfaces and endpoints] -* [Juju] -* [Legacy charm] - -## Operational concepts -* [Users] -* [Logs] -* [Connection pooling] - -## Security and hardening -* [Security hardening guide][Security] - * [Cryptography] - -## Development -Charm event flowcharts: -* [Charm] -* [Relations] -* [Backups] - - - -[Architecture]: /t/11856 -[Interfaces and endpoints]: /t/10252 -[Users]: /t/10843 -[Logs]: /t/12098 -[Juju]: /t/11986 -[Legacy charm]: /t/11013 -[Connection pooling]: /t/15799 -[Charm]: /t/9305 -[Relations]: /t/9306 -[Backups]: /t/10248 -[Security]: /t/16850 -[Cryptography]: /t/16851 \ No newline at end of file diff --git a/docs/explanation/architecture-diagram.png b/docs/explanation/architecture-diagram.png new file mode 100644 index 0000000000..eb4b586859 Binary files /dev/null and b/docs/explanation/architecture-diagram.png differ diff --git a/docs/explanation/e-architecture.md b/docs/explanation/architecture.md similarity index 84% rename from docs/explanation/e-architecture.md rename to docs/explanation/architecture.md index 5817eac91b..f6f6f9230e 100644 --- a/docs/explanation/e-architecture.md +++ b/docs/explanation/architecture.md @@ -2,9 +2,9 @@ [PostgreSQL](https://www.postgresql.org/) is one of the most popular open source database. The “[Charmed PostgreSQL K8s](https://charmhub.io/postgresql-k8s)” is a Juju-based operator to deploy and support PostgreSQL from [day 0 to day 2](https://codilime.com/blog/day-0-day-1-day-2-the-software-lifecycle-in-the-cloud-age/), it is based on the [PostgreSQL Community Edition](https://www.postgresql.org/community/) using the [Patroni](https://github.com/zalando/patroni) to manage PostgreSQL cluster based on [PostgreSQL synchronous replication](https://patroni.readthedocs.io/en/latest/replication_modes.html#postgresql-synchronous-replication). -![image|690x423, 100%](upload://fqMd5JlHeegw0PlUjhWKRu858Nc.png) +![image|690x423, 100%](architecture-diagram.png) -## Juju K8s Concept +## Juju K8s concept The charm design leverages the [sidecar](https://kubernetes.io/blog/2015/06/the-distributed-system-toolkit-patterns/#example-1-sidecar-containers) pattern to allow multiple containers in each pod with [Pebble](https://juju.is/docs/sdk/pebble) running as the workload container’s entrypoint. @@ -12,24 +12,23 @@ Pebble is a lightweight, API-driven process supervisor that is responsible for c Pebble `services` are configured through [layers](https://github.com/canonical/pebble#layer-specification), and the following containers represent each one a layer forming the effective Pebble configuration, or `pebble plan`: -1. a [charm]() container runs Juju operator code: `juju ssh postgresql-k8s/0 bash` -1. a [postgresql](https://www.postgresql.owg/) (workload) container runs the PostgreSQL application along with other services (like monitoring metrics exporters, etc): `juju ssh --container postgresql postgresql-k8s/0 bash` +* a charm container runs Juju operator code: `juju ssh postgresql-k8s/0 bash` +* a workload container runs the [PostgreSQL application](https://www.postgresql.org/) along with other services (like monitoring metrics exporters, etc): `juju ssh --container postgresql postgresql-k8s/0 bash` As a result, if you run a `kubectl get pods` on a namespace named for the Juju model you’ve deployed the "Charmed PostgreSQL K8s" charm into, you’ll see something like the following: -```shell +```text NAME READY STATUS RESTARTS AGE postgresql-k8s-0 2/2 Running 0 65m ``` This shows there are 2 containers in the pod: `charm` and `workload` mentioned above. -And if you run `kubectl describe pod postgresql-k8s-0`, all the containers will have as Command `/charm/bin/pebble`. That’s because Pebble is responsible for the processes startup as explained above (see [troubleshooting](/t/11854) for more details.). +And if you run `kubectl describe pod postgresql-k8s-0`, all the containers will have as Command `/charm/bin/pebble`. That’s because Pebble is responsible for the processes startup as explained above (see [troubleshooting](/reference/troubleshooting) for more details.). - ## HLD (High Level Design) -The "Charmed PostgreSQL K8s" (`workload` container) based on `postgresql-image` resource defined in the [charm metadata.yaml](https://github.com/canonical/postgresql-k8s-operator/blob/main/metadata.yaml). It is an official Canonical "[charmed-postgresql](https://github.com/canonical/charmed-postgresql-rock)" [OCI/Rock](https://ubuntu.com/server/docs/rock-images/introduction) image, which is recursively based on Canonical SNAP “[charmed-postgresql](https://snapcraft.io/charmed-postgresql)” (read more about the SNAP details [here](/t/11857)). +The Charmed PostgreSQL K8s (`workload` container) based on `postgresql-image` resource defined in the [charm metadata.yaml](https://github.com/canonical/postgresql-k8s-operator/blob/main/metadata.yaml). It is an official Canonical [charmed-postgresql](https://github.com/canonical/charmed-postgresql-rock) [OCI/Rock](https://ubuntu.com/server/docs/rock-images/introduction) image, which is recursively based on the Canonical [`charmed-postgresql` snap]. [Charmcraft](https://juju.is/docs/sdk/install-charmcraft) uploads an image as a [charm resource](https://charmhub.io/postgresql-k8s/resources/postgresql-image) to [Charmhub](https://charmhub.io/postgresql-k8s) during the [publishing](https://github.com/canonical/postgresql-k8s-operator/blob/main/.github/workflows/release.yaml), as described in the [Juju SDK How-to guides](https://juju.is/docs/sdk/publishing). @@ -37,18 +36,18 @@ The charm supports Juju deploymed to all Kubernetes environments: [MicroK8s](htt The OCI/Rock ships the following components: -* PostgreSQL Community Edition (based on SNAP "[charmed-postgresql](/t/11857)") -* Patroni (based on SNAP "[charmed-postgresql](/t/11857)") -* PgBouncer (based on SNAP "[charmed-postgresql](/t/11857)") -* pgBackRest (based on SNAP "[charmed-postgresql](/t/11857)") -* Prometheus PostgreSQL Exporter (based on SNAP "[charmed-postgresql](/t/11857)") -* Prometheus PgBouncer Exporter (based on SNAP "[charmed-postgresql](/t/11857)") +* PostgreSQL Community Edition (based on [`charmed-postgresql` snap]) +* Patroni (based on [`charmed-postgresql` snap]) +* PgBouncer (based on [`charmed-postgresql` snap]) +* pgBackRest (based on [`charmed-postgresql` snap]) +* Prometheus PostgreSQL Exporter (based on [`charmed-postgresql` snap]) +* Prometheus PgBouncer Exporter (based on [`charmed-postgresql` snap]) * Prometheus Grafana dashboards and Loki alert rules are part of the charm revision (and missing in SNAP). SNAP-based rock images guarantee the same components versions and functionality between VM and K8s charm flavors. Pebble runs layers of all the currently enabled services, e.g. monitoring, backups, etc: -```shell +```text > juju ssh --container postgresql postgresql-k8s/0 /charm/bin/pebble services Service Startup Current Since metrics_server enabled active today at 21:42 UTC @@ -58,7 +57,7 @@ postgresql enabled active today at 21:42 UTC The `postgresql` is a main Pebble service which is normally up and running right after the charm deployment. -All `metrics_server` Pebble service is activated after the relation with [COS Monitoring](/t/10812) only. +All `metrics_server` Pebble service is activated after the relation with [COS Monitoring](/how-to/monitoring-cos/enable-monitoring) only. > **:information_source: Note:** it is possible to star/stop/restart pebble services manually but it is NOT recommended to avoid a split brain with a charm state machine! Do it with a caution!!! @@ -69,7 +68,6 @@ The rock "charmed-postgresql" also ships list of tools used by charm: * `patronictl` - a tool to monitor/manage Patroni. * `pgbackrest` - a framework to backup and restore PostgreSQL. - ## Integrations ### PgBouncer @@ -98,20 +96,19 @@ GLAuth is a secure, easy-to-use and open-sourced LDAP server which provides capa ### Grafana -Grafana is an open-source visualization tools that allows to query, visualize, alert on, and visualize metrics from mixed datasources in configurable dashboards for observability. This charms is shipped with its own Grafana dashboard and supports integration with the [Grafana Operator](https://charmhub.io/grafana-k8s) to simplify observability. Please follow [COS Monitoring](/t/10812) setup. +Grafana is an open-source visualization tools that allows to query, visualize, alert on, and visualize metrics from mixed datasources in configurable dashboards for observability. This charms is shipped with its own Grafana dashboard and supports integration with the [Grafana Operator](https://charmhub.io/grafana-k8s) to simplify observability. Please follow [COS Monitoring](/how-to/monitoring-cos/enable-monitoring) setup. ### Loki -Loki is an open-source fully-featured logging system. This charms is shipped with support for the [Loki Operator](https://charmhub.io/loki-k8s) to collect the generated logs. Please follow [COS Monitoring](/t/10812) setup. +Loki is an open-source fully-featured logging system. This charms is shipped with support for the [Loki Operator](https://charmhub.io/loki-k8s) to collect the generated logs. Please follow [COS Monitoring](/how-to/monitoring-cos/enable-monitoring) setup. ### Prometheus -Prometheus is an open-source systems monitoring and alerting toolkit with a dimensional data model, flexible query language, efficient time series database and modern alerting approach. This charm is shipped with a Prometheus exporters, alerts and support for integrating with the [Prometheus Operator](https://charmhub.io/prometheus-k8s) to automatically scrape the targets. Please follow [COS Monitoring](/t/10812) setup. +Prometheus is an open-source systems monitoring and alerting toolkit with a dimensional data model, flexible query language, efficient time series database and modern alerting approach. This charm is shipped with a Prometheus exporters, alerts and support for integrating with the [Prometheus Operator](https://charmhub.io/prometheus-k8s) to automatically scrape the targets. Please follow [COS Monitoring](/how-to/monitoring-cos/enable-monitoring) setup. - ## LLD (Low Level Design) -Please check the charm state machines displayed on [workflow diagrams](/t/9305). The low-level logic is mostly common for both VM and K8s charm flavors. +Please check the charm state machines displayed on [workflow diagrams](/explanation/flowcharts/charm). The low-level logic is mostly common for both VM and K8s charm flavors. @@ -133,7 +130,7 @@ For this charm, the following events are observed: The "[src/charm.py](https://github.com/canonical/postgresql-k8s-operator/blob/main/src/charm.py)" is the default entry point for a charm and has the `PostgresqlOperatorCharm` Python class which inherits from CharmBase. -CharmBase is the base class from which all Charms are formed, defined by [Ops](https://juju.is/docs/sdk/ops) (Python framework for developing charms). See more information in [Charm](https://juju.is/docs/sdk/constructs#heading--charm). +CharmBase is the base class from which all Charms are formed, defined by [Ops](https://juju.is/docs/sdk/ops) (Python framework for developing charms). See more information in [Charm](https://juju.is/docs/sdk/constructs#charm). The `__init__` method guarantees that the charm observes all events relevant to its operation and handles them. @@ -143,4 +140,8 @@ The VM and K8s charm flavors shares the codebase via [charm libraries](https://j Library name API Patch postgresql 0 12 postgresql_tls 0 7 -``` \ No newline at end of file +``` + + + +[`charmed-postgresql` snap]: https://snapcraft.io/charmed-postgresql \ No newline at end of file diff --git a/docs/explanation/e-connection-pooling.md b/docs/explanation/connection-pooling.md similarity index 80% rename from docs/explanation/e-connection-pooling.md rename to docs/explanation/connection-pooling.md index 882ed9288e..63886c0196 100644 --- a/docs/explanation/e-connection-pooling.md +++ b/docs/explanation/connection-pooling.md @@ -10,8 +10,9 @@ A way to achieve this with Charmed PostgreSQL K8s is by integrating with the [Pg If using PgBouncer is not enough to handle the connections load of your application, you can increase the amount of connections that PostgreSQL can open via the [`experimental_max_connections` config parameter](https://charmhub.io/postgresql-k8s/configurations#experimental_max_connections). -[note type="caution"] -**Disclaimer:** Each connection opened by PostgreSQL spawns a new process, which is resource-intensive. Use this option as a last resort. +```{caution} +Each connection opened by PostgreSQL spawns a new process, which is resource-intensive. Use this option as a last resort. + +[Contact us](/reference/contacts) for more guidance for your use-case. +``` -[Contact us](/t/11852) for more guidance about your use-case. -[/note] \ No newline at end of file diff --git a/docs/explanation/e-flowchart-backups.md b/docs/explanation/flowcharts/backups.md similarity index 93% rename from docs/explanation/e-flowchart-backups.md rename to docs/explanation/flowcharts/backups.md index e97a23b9d9..0a256c0823 100644 --- a/docs/explanation/e-flowchart-backups.md +++ b/docs/explanation/flowcharts/backups.md @@ -1,13 +1,14 @@ # Backup flowcharts + This document contains backups management flowchart, including all major hooks. This sources can be found at [src/backups.py](https://github.com/canonical/postgresql-k8s-operator/blob/main/src/backups.py). -## Hook Handler Flowcharts +## Hook handler flowcharts + These flowcharts detail the control flow of the hooks in this program. Unless otherwise stated, **a hook deferral is always followed by a return**. -## On S3 Credentials Changed Hook -[Click to navigate the mermaid diagram on GitHub](https://github.com/canonical/postgresql-k8s-operator/blob/main/docs/explanation/e-backups.md). +## On `s3-credentials-changed` hook -```mermaid +```{mermaid} flowchart TD hook_fired([s3-credentials-changed Hook]) --> has_cluster_initialised{Has cluster\n initialised?} has_cluster_initialised -- no --> defer>defer] @@ -35,10 +36,9 @@ flowchart TD When certificates are received from TLS certificates operator through the `certificates` relation (or the relation is removed) the steps starting from `Is TLS disabled or single unit cluster` are also executed. -## On Create Backup Hook -[Click to navigate the mermaid diagram on GitHub](https://github.com/canonical/postgresql-k8s-operator/blob/main/docs/explanation/e-backups.md). +## On `create-backup` hook -```mermaid +```{mermaid} flowchart TD hook_fired([create-backup Hook]) --> is_blocked{Is unit in\nblocked state?} is_blocked -- yes --> fail_action([fail action]) @@ -70,10 +70,10 @@ flowchart TD finish_action --> is_replica2 ``` -## On List Backups Hook +## On `list-backups` hook [Click to navigate the mermaid diagram on GitHub](https://github.com/canonical/postgresql-k8s-operator/blob/main/docs/explanation/e-backups.md). -```mermaid +```{mermaid} flowchart TD hook_fired([list-backups Hook]) --> is_s3_relation_established{Is S3 relation\nestablished?} is_s3_relation_established -- no --> fail_action([fail action]) @@ -84,10 +84,10 @@ flowchart TD does_pgbackrest_returned_backups_list -- yes --> return_formatted_backup_list[Return formatted\nbackup list] ``` -## On Restore Hook +## On `restore` hook [Click to navigate the mermaid diagram on GitHub](https://github.com/canonical/postgresql-k8s-operator/blob/main/docs/explanation/e-backups.md). -```mermaid +```{mermaid} flowchart TD hook_fired([restore Hook]) --> has_user_provided_backup_id{Has user provided\na backup id?} has_user_provided_backup_id -- no --> fail_action([fail action]) @@ -115,4 +115,5 @@ flowchart TD ``` The unit status becomes `Active` or `Blocked` after a, respectively, successful or failed restore -is detected in the update status hook. \ No newline at end of file +is detected in the update status hook. + diff --git a/docs/explanation/e-flowchart-charm.md b/docs/explanation/flowcharts/charm.md similarity index 87% rename from docs/explanation/e-flowchart-charm.md rename to docs/explanation/flowcharts/charm.md index f9eafe8c72..1720a22e84 100644 --- a/docs/explanation/e-flowchart-charm.md +++ b/docs/explanation/flowcharts/charm.md @@ -6,10 +6,9 @@ The file `charm.py` is the entrypoint for the charm. It contains functions for i These flowcharts detail the control flow of the hooks in this program. Unless otherwise stated, **a hook deferral is always followed by a return**. -## Leader Elected Hook -[Click to navigate the mermaid diagram on GitHub](https://github.com/canonical/postgresql-k8s-operator/blob/e760a3df8ceceab49357ff57c620299d9d101fc8/docs/explanation/flowcharts/e-flowchart-charm.md). +## `leader-elected` hook -```mermaid +```{mermaid} flowchart TD hook_fired([leader-elected Hook]) --> generate_passwords{Generate password for charm users?} generate_passwords --> create_k8s_resources[Create k8s resources\n needed by Patroni] @@ -33,10 +32,9 @@ flowchart TD update_config --> rtn2([return]) ``` -## PostgreSQL Pebble Ready Hook -[Click to navigate the mermaid diagram on GitHub](https://github.com/canonical/postgresql-k8s-operator/blob/e760a3df8ceceab49357ff57c620299d9d101fc8/docs/explanation/flowcharts/e-flowchart-charm.md). +## PostgreSQL Pebble ready hook -```mermaid +```{mermaid} flowchart TD hook_fired([leader-elected Hook]) --> create_pgdata{Create data\n directory} create_pgdata --> is_leader_or_has_cluster_initialised{Is current unit\n leader or has the \n cluster initialised?} @@ -60,4 +58,5 @@ flowchart TD mark_cluster_as_initialised--> update_config[Turn on/off PostgreSQL \n synchronous_commit configuration] update_config --> set_active[Set Active\n Status] set_active --> rtn2([return]) -``` \ No newline at end of file +``` + diff --git a/docs/explanation/flowcharts/index.md b/docs/explanation/flowcharts/index.md new file mode 100644 index 0000000000..98f38698e3 --- /dev/null +++ b/docs/explanation/flowcharts/index.md @@ -0,0 +1,10 @@ +# Flowcharts + +```{toctree} +:titlesonly: +:maxdepth: 2 +:glob: + +Charm +Backups +Relations diff --git a/docs/explanation/e-flowchart-peers.md b/docs/explanation/flowcharts/relations.md similarity index 88% rename from docs/explanation/e-flowchart-peers.md rename to docs/explanation/flowcharts/relations.md index ce956c503d..b811e3606d 100644 --- a/docs/explanation/e-flowchart-peers.md +++ b/docs/explanation/flowcharts/relations.md @@ -2,18 +2,17 @@ This reference documentation details the implementation of the `database-peers` peer relation. This is the peer relation for PostgreSQL, used to share user and config information from the leader unit to the follower units. The file implementing these relations can be found here: [src/relations/charm.py](https://github.com/canonical/postgresql-k8s-operator/blob/main/src/charm.py) (it should be moved to a file called `src/relations/peers.py` in the future). -## Expected Interface +## Expected interface These are the expected contents of the databags in this relation (all values are examples, generated in a running test instance): -## Hook Handler Flowcharts +## Hook handler flowcharts These flowcharts detail the control flow of the hooks in this program. Unless otherwise stated, **a hook deferral is always followed by a return**. -## Peer Relation Changed Hook -[Click to navigate the mermaid diagram on GitHub](https://github.com/canonical/postgresql-k8s-operator/blob/main/docs/explanation/e-peers.md). +## `peer-relation-changed` hook -```mermaid +```{mermaid} flowchart TD hook_fired([peer-relation-changed Hook]) --> has_cluster_initialised{Has cluster\n initialised?} has_cluster_initialised -- no --> defer>defer] @@ -43,10 +42,9 @@ flowchart TD set_active --> rtn2([return]) ``` -## Peer Relation Departed Hook -[Click to navigate the mermaid diagram on GitHub](https://github.com/canonical/postgresql-k8s-operator/blob/main/docs/explanation/e-peers.md). +## `peer-relation-departed` hook -```mermaid +```{mermaid} flowchart TD hook_fired([peer-relation-changed Hook]) --> is_leader_and_is_not_departing{Is leader and \n is not departing?} is_leader_and_is_not_departing -- no --> rtn([return]) @@ -58,4 +56,5 @@ flowchart TD update_read_only_endpoint --> remove_departing_units[Remove departing units \n from the cluster] remove_departing_units --> update_config[Turn on/off PostgreSQL \n synchronous_commit configuration] update_config --> rtn2([return]) -``` \ No newline at end of file +``` + diff --git a/docs/explanation/index.md b/docs/explanation/index.md new file mode 100644 index 0000000000..55554e617e --- /dev/null +++ b/docs/explanation/index.md @@ -0,0 +1,56 @@ +# Explanation + +Additional context about key concepts behind the PostgreSQL charm, including design and legacy information. + +## Core concepts and design +* [Architecture] +* [Interfaces and endpoints] +* [Juju] +* [Legacy charm] + +## Operational concepts +* [Users] +* [Logs] +* [Connection pooling] + +## Security and hardening +* [Security hardening guide][Security] + * [Cryptography] + +## Development +Charm event flowcharts: +* [Charm] +* [Relations] +* [Backups] + + + +[Architecture]: /explanation/architecture +[Interfaces and endpoints]: /explanation/interfaces-endpoints +[Users]: /explanation/users +[Logs]: /explanation/logs +[Juju]: /explanation/juju +[Legacy charm]: /explanation/legacy-charm +[Connection pooling]: /explanation/connection-pooling +[Charm]: /explanation/flowcharts/charm +[Relations]: /explanation/flowcharts/relations +[Backups]: /explanation/flowcharts/backups +[Security]: /explanation/security/index +[Cryptography]: /explanation/security/cryptography + + +```{toctree} +:titlesonly: +:maxdepth: 2 +:glob: +:hidden: + +Architecture +Interfaces and endpoints +Juju +Legacy charm +Users +Logs +Connection pooling +Security +Flowcharts \ No newline at end of file diff --git a/docs/explanation/e-interfaces-endpoints.md b/docs/explanation/interfaces-endpoints.md similarity index 68% rename from docs/explanation/e-interfaces-endpoints.md rename to docs/explanation/interfaces-endpoints.md index d36683d885..bfeba89cff 100644 --- a/docs/explanation/e-interfaces-endpoints.md +++ b/docs/explanation/interfaces-endpoints.md @@ -2,7 +2,9 @@ The charm supports modern `postgresql_client` and legacy `pgsql` interfaces (in a backward compatible mode). -**Note:** do NOT relate both modern and legacy interfaces simultaneously! +```{caution} +Do **not** relate both modern and legacy interfaces simultaneously! +``` ## Modern interfaces @@ -12,9 +14,9 @@ This charm provides modern ['postgresql_client'](https://github.com/canonical/ch Adding a relation is accomplished with `juju relate` (or `juju integrate` for Juju 3.x) via endpoint `database`. Example: -```shell +```text # Deploy Charmed PostgreSQL cluster with 3 nodes -juju deploy postgresql-k8s -n 3 --trust --channel 14 +juju deploy postgresql-k8s --channel 14/stable -n 3 --trust # Deploy the relevant application charms juju deploy mycharm @@ -30,20 +32,27 @@ juju status --relations # > postgresql-k8s:database mycharm:database postgresql_client regular ``` -Find all details about default and extra DB user roles in "[Charm Users explanations](/t/10843)". +Find all details about default and extra DB user roles in [](/explanation/users)". ## Legacy interfaces -**Note:** Legacy relations are deprecated and will be discontinued on future releases. Usage should be avoided. Check the legacy interface implementation limitations in the "[Legacy charm](/t/11013)" document. +```{note} +Legacy relations are deprecated and will be discontinued on future releases. Their usage should be avoided. + +Check the legacy interfaces implementation limitations in [](/explanation/legacy-charm)" +``` ### Legacy `pgsql` interface (`db` and `db-admin` endpoints): This charm supports legacy interface `pgsql` from the previous [PostgreSQL charm](https://launchpad.net/postgresql-charm): -```shell -juju deploy postgresql-k8s --trust --channel 14 +```text +juju deploy postgresql-k8s --channel 14/stable --trust juju deploy finos-waltz-k8s --channel edge juju relate postgresql-k8s:db finos-waltz-k8s ``` -**Note:** The endpoint `db-admin` provides the same legacy interface `pgsql` with PostgreSQL admin-level privileges. It is NOT recommended to use it from security point of view. \ No newline at end of file +```{note} +The endpoint `db-admin` provides the same legacy interface `pgsql` with PostgreSQL admin-level privileges. It is NOT recommended to use it due to security limitations. +``` + diff --git a/docs/explanation/e-juju-details.md b/docs/explanation/juju.md similarity index 75% rename from docs/explanation/e-juju-details.md rename to docs/explanation/juju.md index 9088e6f93f..806ade4498 100644 --- a/docs/explanation/e-juju-details.md +++ b/docs/explanation/juju.md @@ -1,11 +1,13 @@ # Juju + [Juju](https://juju.is/) is an open source orchestration engine for software operators that enables the deployment, integration and lifecycle management of applications at any scale, on any infrastructure using charms. > See also: [Juju client documentation](https://juju.is/docs/juju), [Juju blog](https://ubuntu.com/blog/tag/juju) ## Compatibility with PostgreSQL + Current stable releases of this charm can still be deployed on Juju 2.9. However, newer features are not supported. -> See the [Releases page](/t/11872) for more information about the minimum Juju version required to operate the features of each revision. +> See the [Releases page](/reference/releases) for more information about the minimum Juju version required to operate the features of each revision. Additionally, there are limitations regarding integrations with other charms. For example, integration with [modern TLS charms](https://charmhub.io/topics/security-with-x-509-certificates) requires Juju 3.x. @@ -15,7 +17,7 @@ As this charm's documentation is written for Juju 3.x, users of 2.9.x will encou Breaking changes have been introduced in the Juju client between versions 2.9.x and 3.x. These are caused by the renaming and re-purposing of several commands - functionality and command options remain unchanged. -In the context of this guide, the pertinent changes are as follows: +In the context of this documentation, the pertinent changes are as follows: | v2.9.x | v3.x | | --- | --- | @@ -24,20 +26,25 @@ In the context of this guide, the pertinent changes are as follows: |`run`|`exec`| |`run-action --wait`|`run`| -See the [Juju 3.0 release notes](https://juju.is/docs/juju/roadmap#heading--juju-3-0-0---22-oct-2022) for the comprehensive list of changes. +See the [Juju 3.0 release notes](https://juju.is/docs/juju/roadmap#juju-3-0-0---22-oct-2022) for the comprehensive list of changes. Example substitutions: -### Juju 3.x: -```shell +**Juju 3.x:** + +```text juju integrate postgresql-k8s:database postgresql-test-app juju run postgresql-k8s/leader get-password ``` -### Juju 2.9.x: -```shell + +**Juju 2.9.x:** + +```text juju relate postgresql-k8s:database postgresql-test-app juju run-action --wait postgresql-k8s/leader get-password ``` -> :tipping_hand_man: [The document based on OpenStack guide.](https://docs.openstack.org/charm-guide/latest/project/support-notes.html#breaking-changes-between-juju-2-9-x-and-3-x) \ No newline at end of file + +> This document is based on [this OpenStack guide](https://docs.openstack.org/charm-guide/latest/project/support-notes.html#breaking-changes-between-juju-2-9-x-and-3-x) + diff --git a/docs/explanation/e-legacy-charm.md b/docs/explanation/legacy-charm.md similarity index 71% rename from docs/explanation/e-legacy-charm.md rename to docs/explanation/legacy-charm.md index d0998829ef..3efbf6fc58 100644 --- a/docs/explanation/e-legacy-charm.md +++ b/docs/explanation/legacy-charm.md @@ -1,25 +1,27 @@ -## Charm types "legacy" vs "modern" -There are [two types of charms](https://juju.is/docs/sdk/charm-taxonomy#heading--charm-types-by-generation) stored under the same charm name `postgresql-k8s`: +# Legacy charm -1. [Reactive](https://juju.is/docs/sdk/charm-taxonomy#heading--reactive) charm in the channel `latest/stable` (called `legacy`) +There are [two types of charms](https://juju.is/docs/sdk/charm-taxonomy#charm-types-by-generation) stored under the same charm name `postgresql-k8s`: + +1. [Reactive](https://juju.is/docs/sdk/charm-taxonomy#reactive) charm in the channel `latest/stable` (called `legacy`) 2. [Ops-based](https://juju.is/docs/sdk/ops) charm in the channel `14/stable` (called `modern`) The legacy charm provided endpoints `db` and `db-admin` (for the interface `pgsql`). The modern charm provides old endpoints as well + new endpoint `database` (for the interface `postgresql_client`). Read more details about the available [endpoints/interfaces](https://charmhub.io/postgresql-k8s/docs/e-interfaces). -**Note**: Please choose one endpoint to use. No need to relate all of them simultaneously! +```{note} +Choose one endpoint to use, rather than relating both simultaneously. +``` ## The default track "latest" vs "14" The [default track](https://docs.openstack.org/charm-guide/yoga/project/charm-delivery.html) has been switched from the `latest` to `14` for both VM and K8s PostgreSQL charms. It is [to ensure](https://discourse.charmhub.io/t/request-switch-default-track-from-latest-to-14-for-postgresql-k8s-charms/10314) all new deployments use a modern codebase. We strongly advise against using the latest track due to its implicit nature. In doing so, a future charm upgrade may result in a PostgreSQL version incompatible with an integrated application. Track 14 guarantees PostgreSQL 14 deployment only. The track `latest` will be closed after all applications migrated from Reactive to Ops-based charm. - ## How to migrate from "legacy" to "modern" charm The "modern" charm provides temporary support for the legacy interfaces: * **quick try**: relate the current application with new charm using endpoint `db` (set the channel to `14/stable`). No extra changes necessary: -``` +```text postgresql: charm: postgresql-k8s channel: 14/stable @@ -28,21 +30,33 @@ The "modern" charm provides temporary support for the legacy interfaces: * **proper migration**: migrate the application to the new interface "[postgresql_client](https://github.com/canonical/charm-relation-interfaces)". The application will connect PostgreSQL using "[data_interfaces](https://charmhub.io/data-platform-libs/libraries/data_interfaces)" library from "[data-platform-libs](https://github.com/canonical/data-platform-libs/)" via endpoint `database`. -**Warning**: NO in-place upgrades possible! Reactive charm cannot be upgraded to Operator-framework-based one. To move DB data, the second/modern DB application must be launched nearby and data should be copied from "legacy" application to the "modern" one. Canonical Data Platform team is preparing copy&paste guide right now. Please [contact us](https://chat.charmhub.io/charmhub/channels/data-platform) if you need migration instructions. +Note that the `trust` option must be enabled if [Role Based Access Control (RBAC)](https://kubernetes.io/docs/concepts/security/rbac-good-practices/) is in use on your Kubernetes. -**Note**: the `trust` option must be enabled if [ Role Based Access Control (RBAC)](https://kubernetes.io/docs/concepts/security/rbac-good-practices/) is in use on your Kubernetes. +```{warning} +**In-place upgrades are not supported for this case.** + +Reactive charms cannot be upgraded to an operator-framework-based version. To move database data, the new DB application must be launched nearby, and data should be copied from "legacy" application to the "modern" one. + +Please [contact us](https://chat.charmhub.io/charmhub/channels/data-platform) if you need migration instructions. +``` ## How to deploy old "legacy" postgresql charm Deploy the charm using the channel `latest/stable`: -``` +```text postgresql: charm: postgresql-k8s channel: latest/stable ``` -**Note**: remove Charm store prefix `cs:` from the bundle. Otherwise the modern charm will be chosen by Juju (due to the default track pointing to `14/stable` and not `latest/stable`). The common error message is: `cannot deploy application "postgresql": unknown option "..."`. +```{caution} +Remove the charm store prefix `cs:` from the bundle. + +Otherwise, the modern charm will be chosen by Juju (due to the default track pointing to `14/stable` and not `latest/stable`). + +A common error message is: `cannot deploy application "postgresql": unknown option "..."`. +``` ## Config options supported by modern charm @@ -52,11 +66,11 @@ The legacy charm config options were not moved to the modern charm due to no nee The legacy charm provided plugins/extensions enabling through the relation (interface `pgsql`). It is NOT supported by the modern charm (neither `pgsql` nor `postgresql_client` interfaces). Please enable the necessary extensions using appropriate `plugin_*_enable` [config option](https://charmhub.io/postgresql-k8s/configure) of the modern charm. After enabling the modern charm will provide plugins support for both `pgsql` and `postgresql_client` interfaces. -Please find the list of supported PostgreSQL [Extensions](/t/10945) by modern charm. Feel free to [contact us](/t/11852) with a list of required extensions. +Please find the list of supported PostgreSQL [Extensions](/reference/plugins-extensions) by modern charm. Feel free to [contact us](/reference/contacts) with a list of required extensions. ## Roles supported by modern charm -In the legacy charm, the user could request roles by setting the `roles` field to a comma separated list of desired roles. It is NOT supported by the modern charm implementation of the legacy `pgsql` interface. The same functionality is provided via the modern `postgresql_client` using "[extra-user-roles](/t/10843#extra-user-roles)". Please check how to [migrate on the new interface](/t/11853). +In the legacy charm, the user could request roles by setting the `roles` field to a comma separated list of desired roles. It is NOT supported by the modern charm implementation of the legacy `pgsql` interface. The same functionality is provided via the modern `postgresql_client` using "[extra-user-roles](/explanation/users)". Please check how to [migrate on the new interface](/how-to/development/integrate-with-your-charm). ## Supported PostgreSQL versions by modern charm @@ -66,7 +80,7 @@ Please [contact us](https://chat.charmhub.io/charmhub/channels/data-platform) if ## Supported architectures: amd64, arm64, ... Currently, the charm supports architecture `amd64` (all revisions) and `arm64` (from revision 211+). -See the technical details in [Supported architectures](/t/11744) +See the technical details in [Supported architectures](/reference/system-requirements) ## How to report issues and contact authors @@ -74,4 +88,5 @@ The "legacy charm" (from `latest/stable`) is stored on [Launchpad](https://git.l The "modern charm" (from `14/stable`) is stored on [GitHub](https://github.com/canonical/postgresql-k8s-operator), here is the link to report [modern charm issues](https://github.com/canonical/postgresql-k8s-operator/issues/new/choose). -Do you have questions? [Contact us](https://chat.charmhub.io/charmhub/channels/data-platform)! \ No newline at end of file +Do you have questions? [Contact us](https://chat.charmhub.io/charmhub/channels/data-platform)! + diff --git a/docs/explanation/e-logs.md b/docs/explanation/logs.md similarity index 95% rename from docs/explanation/e-logs.md rename to docs/explanation/logs.md index fdbb5d8557..5617d28b18 100644 --- a/docs/explanation/e-logs.md +++ b/docs/explanation/logs.md @@ -1,12 +1,14 @@ # Logs -The list of all the charm components are well described in the "[Architecture](/t/11856)". -It is a dedicated section to highlight logs for each component to simplify troubleshooting. +This page summarizes all log types in Charmed PostgreSQL to simplify troubleshooting. + +For an overview of all charm components, see [](/explanation/architecture). ## Core logs PostgreSQL and Patroni logs can be found in `/var/log/postgresql` within the `postgresql` container of each unit: -```shell + +```text > ls -alh /var/log/postgresql/ total 60K drwxr-xr-x 1 postgres root 4.0K Oct 11 11:45 . @@ -27,8 +29,10 @@ drwxr-xr-x 1 root root 4.0K Aug 18 12:53 .. -rw------- 1 postgres postgres 0 Oct 11 11:44 postgresql-3_1144.log -rw------- 1 postgres postgres 0 Oct 11 11:45 postgresql-3_1145.log ``` + The PostgreSQL log naming convention is `postgresql-_.log`. The log message format is `