Skip to content

Commit

Permalink
bug: configure maximum db connections (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
skatsaounis authored Jul 11, 2024
1 parent e71c186 commit 423ea89
Show file tree
Hide file tree
Showing 11 changed files with 260 additions and 50 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ ubuntu@infra1:~$ maas-anvil cluster bootstrap \
Note: You will be asked for a `virtual_ip` during installation of the HAProxy charm, if `accept-defaults` is omitted.
Pass an empty value to disable it, or any valid IP to enable; the Keepalived charm will be installed to enable connecting to HA MAAS using the VIP.

#### PostgreSQL max_connections

You will be asked for a `max_connections` during installation of the PostgreSQL charm, if `accept-defaults` is omitted. Use `default` if you need the default values of PostgreSQL to be applied to [max_connections](https://www.postgresql.org/docs/14/runtime-config-connection.html). If you are aiming for MAAS HA though you have to do one of the following:

- If number of MAAS region nodes is known beforehand, you can calculate the desired max_connections and set them, based on the formula: `max_connections = max(100, 10 + 50 * number_of_region_nodes)`.
- If number of MAAS region nodes is not known, you can set `max_connections` to `dynamic` and let MAAS Anvil recalculate the appropriate PostgreSQL `max_connections` every time a region node is joining or leaving the Anvil cluster. **This options includes a database restart with every modification.**

### Add new nodes to the MAAS cluster

```bash
Expand Down
13 changes: 4 additions & 9 deletions anvil-python/anvil/commands/maas_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,15 @@

from sunbeam.clusterd.client import Client
from sunbeam.commands.terraform import TerraformInitStep
from sunbeam.jobs.common import BaseStep
from sunbeam.jobs.juju import JujuHelper
from sunbeam.jobs.manifest import BaseStep
from sunbeam.jobs.steps import (
AddMachineUnitsStep,
DeployMachineApplicationStep,
RemoveMachineUnitStep,
)

from anvil.jobs.manifest import Manifest
from anvil.provider.local.deployment import LocalDeployment

APPLICATION = "maas-agent"
CONFIG_KEY = "TerraformVarsMaasagentPlan"
Expand Down Expand Up @@ -116,15 +115,11 @@ def maas_agent_install_steps(
client: Client,
manifest: Manifest,
jhelper: JujuHelper,
deployment: LocalDeployment,
model: str,
fqdn: str,
) -> List[BaseStep]:
return [
TerraformInitStep(manifest.get_tfhelper("maas-agent-plan")),
DeployMAASAgentApplicationStep(
client, manifest, jhelper, deployment.infrastructure_model
),
AddMAASAgentUnitsStep(
client, fqdn, jhelper, deployment.infrastructure_model
),
DeployMAASAgentApplicationStep(client, manifest, jhelper, model),
AddMAASAgentUnitsStep(client, fqdn, jhelper, model),
]
13 changes: 4 additions & 9 deletions anvil-python/anvil/commands/maas_region.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,15 @@

from sunbeam.clusterd.client import Client
from sunbeam.commands.terraform import TerraformInitStep
from sunbeam.jobs.common import BaseStep
from sunbeam.jobs.juju import JujuHelper
from sunbeam.jobs.manifest import BaseStep
from sunbeam.jobs.steps import (
AddMachineUnitsStep,
DeployMachineApplicationStep,
RemoveMachineUnitStep,
)

from anvil.jobs.manifest import Manifest
from anvil.provider.local.deployment import LocalDeployment

APPLICATION = "maas-region"
CONFIG_KEY = "TerraformVarsMaasregionPlan"
Expand Down Expand Up @@ -124,15 +123,11 @@ def maas_region_install_steps(
client: Client,
manifest: Manifest,
jhelper: JujuHelper,
deployment: LocalDeployment,
model: str,
fqdn: str,
) -> List[BaseStep]:
return [
TerraformInitStep(manifest.get_tfhelper("maas-region-plan")),
DeployMAASRegionApplicationStep(
client, manifest, jhelper, deployment.infrastructure_model
),
AddMAASRegionUnitsStep(
client, fqdn, jhelper, deployment.infrastructure_model
),
DeployMAASRegionApplicationStep(client, manifest, jhelper, model),
AddMAASRegionUnitsStep(client, fqdn, jhelper, model),
]
162 changes: 141 additions & 21 deletions anvil-python/anvil/commands/postgresql.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,27 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import List
import logging
from typing import Any, List

from rich.status import Status
from sunbeam.clusterd.client import Client
from sunbeam.commands.terraform import TerraformInitStep
from sunbeam.jobs import questions
from sunbeam.jobs.common import BaseStep, Result, ResultType
from sunbeam.jobs.juju import JujuHelper
from sunbeam.jobs.manifest import BaseStep
from sunbeam.jobs.steps import (
AddMachineUnitsStep,
DeployMachineApplicationStep,
RemoveMachineUnitStep,
)

from anvil.jobs.manifest import Manifest
from anvil.provider.local.deployment import LocalDeployment

LOG = logging.getLogger(__name__)
APPLICATION = "postgresql"
CONFIG_KEY = "TerraformVarsPostgresqlPlan"
POSTGRESQL_CONFIG_KEY = "TerraformVarsPostgresql"
POSTGRESQL_APP_TIMEOUT = (
180 # 3 minutes, managing the application should be fast
)
Expand All @@ -38,15 +42,66 @@
)


def postgresql_install_steps(
client: Client,
manifest: Manifest,
jhelper: JujuHelper,
model: str,
fqdn: str,
accept_defaults: bool,
preseed: dict[Any, Any],
) -> List[BaseStep]:
return [
TerraformInitStep(manifest.get_tfhelper("postgresql-plan")),
DeployPostgreSQLApplicationStep(
client,
manifest,
jhelper,
model,
accept_defaults=accept_defaults,
deployment_preseed=preseed,
),
AddPostgreSQLUnitsStep(client, fqdn, jhelper, model),
]


def postgresql_questions() -> dict[str, questions.PromptQuestion]:
return {
"max_connections": questions.PromptQuestion(
"Maximum number of concurrent connections to allow to the database server",
default_value="default",
validation_function=validate_max_connections,
),
}


def validate_max_connections(value: str) -> str | ValueError:
if value in ["default", "dynamic"]:
return value
try:
if 100 <= int(value) <= 500:
return value
else:
raise ValueError
except ValueError:
raise ValueError(
"Please provide either a number between 100 and 500 or 'default' for system default or 'dynamic' for calculating max_connections relevant to maas regions"
)


class DeployPostgreSQLApplicationStep(DeployMachineApplicationStep):
"""Deploy PostgreSQL application using Terraform"""

_CONFIG = POSTGRESQL_CONFIG_KEY

def __init__(
self,
client: Client,
manifest: Manifest,
jhelper: JujuHelper,
model: str,
deployment_preseed: dict[Any, Any] | None = None,
accept_defaults: bool = False,
refresh: bool = False,
):
super().__init__(
Expand All @@ -62,9 +117,92 @@ def __init__(
refresh,
)

self.preseed = deployment_preseed or {}
self.accept_defaults = accept_defaults

def get_application_timeout(self) -> int:
return POSTGRESQL_APP_TIMEOUT

def prompt(self, console: questions.Console | None = None) -> None:
variables = questions.load_answers(self.client, self._CONFIG)
variables.setdefault("max_connections", "default")

# Set defaults
self.preseed.setdefault("max_connections", "default")

postgresql_config_bank = questions.QuestionBank(
questions=postgresql_questions(),
console=console,
preseed=self.preseed.get("postgres"),
previous_answers=variables,
accept_defaults=self.accept_defaults,
)
max_connections = postgresql_config_bank.max_connections.ask()
variables["max_connections"] = max_connections

LOG.debug(variables)
questions.write_answers(self.client, self._CONFIG, variables)

def extra_tfvars(self) -> dict[str, Any]:
variables: dict[str, Any] = questions.load_answers(
self.client, self._CONFIG
)
variables["maas_region_nodes"] = len(
self.client.cluster.list_nodes_by_role("region")
)
return variables

def has_prompts(self) -> bool:
return True


class ReapplyPostgreSQLTerraformPlanStep(DeployMachineApplicationStep):
"""Reapply PostgreSQL Terraform plan"""

_CONFIG = POSTGRESQL_CONFIG_KEY

def __init__(
self,
client: Client,
manifest: Manifest,
jhelper: JujuHelper,
model: str,
):
super().__init__(
client,
manifest,
jhelper,
CONFIG_KEY,
APPLICATION,
model,
"postgresql-plan",
"Reapply PostgreSQL Terraform plan",
"Reapplying PostgreSQL Terraform plan",
True,
)

def get_application_timeout(self) -> int:
return POSTGRESQL_APP_TIMEOUT

def extra_tfvars(self) -> dict[str, Any]:
variables: dict[str, Any] = questions.load_answers(
self.client, self._CONFIG
)
variables["maas_region_nodes"] = len(
self.client.cluster.list_nodes_by_role("region")
)
return variables

def is_skip(self, status: Status | None = None) -> Result:
variables: dict[str, Any] = questions.load_answers(
self.client, self._CONFIG
)
variables.setdefault("max_connections", "default")
if variables["max_connections"] != "dynamic":
return Result(ResultType.SKIPPED)
else:
return super().is_skip(status)


class AddPostgreSQLUnitsStep(AddMachineUnitsStep):
"""Add PostgreSQL Unit."""
Expand Down Expand Up @@ -110,21 +248,3 @@ def __init__(

def get_unit_timeout(self) -> int:
return POSTGRESQL_UNIT_TIMEOUT


def postgresql_install_steps(
client: Client,
manifest: Manifest,
jhelper: JujuHelper,
deployment: LocalDeployment,
fqdn: str,
) -> List[BaseStep]:
return [
TerraformInitStep(manifest.get_tfhelper("postgresql-plan")),
DeployPostgreSQLApplicationStep(
client, manifest, jhelper, deployment.infrastructure_model
),
AddPostgreSQLUnitsStep(
client, fqdn, jhelper, deployment.infrastructure_model
),
]
Loading

0 comments on commit 423ea89

Please sign in to comment.