Istio Pilot
- Kubeflow Charmers
Channel | Revision | Published | Runs on |
---|---|---|---|
latest/candidate | 69 | 06 Apr 2022 | |
latest/beta | 1013 | 09 Jul 2024 | |
latest/edge | 1235 | 08 Oct 2024 | |
1.22/stable | 1169 | 27 Aug 2024 | |
1.22/edge | 1234 | 08 Oct 2024 | |
1.21/stable | 1170 | 27 Aug 2024 | |
1.21/edge | 1170 | 27 Aug 2024 | |
1.20/stable | 1155 | 27 Aug 2024 | |
1.20/edge | 1198 | 04 Sep 2024 | |
1.19/stable | 1172 | 27 Aug 2024 | |
1.19/edge | 1172 | 27 Aug 2024 | |
1.18/stable | 1173 | 27 Aug 2024 | |
1.18/edge | 1173 | 27 Aug 2024 | |
1.17/stable | 1171 | 27 Aug 2024 | |
1.17/edge | 1197 | 04 Sep 2024 | |
1.16/stable | 662 | 09 Oct 2023 | |
1.16/beta | 413 | 03 Apr 2023 | |
1.16/edge | 970 | 11 Jun 2024 |
juju deploy istio-pilot --channel 1.22/stable
Deploy Kubernetes operators easily with Juju, the Universal Operator Lifecycle Manager. Need a Kubernetes cluster? Install MicroK8s to create a full CNCF-certified Kubernetes system in under 60 seconds.
Platform:
charms.istio_pilot.v0.istio_gateway_info
-
- Last updated 24 Jul 2023
- Revision Library version 0.4
#!/usr/bin/env python3
# Copyright 2023 Canonical Ltd.
# See LICENSE file for licensing details.
"""Library for sharing Istio Gateway(s) information.
This library offers a Python API for providing and requesting information about
Istio Gateway(s) by wrapping the `gateway-info` relation endpoints.
The default relation name is `gateway-info` and it's recommended to use that name,
though if changed, you must ensure to pass the correct name when instantiating the
provider and requirer classes, as well as in `metadata.yaml`.
## Getting Started
### Fetching the library with charmcraft
Using charmcraft you can:
```shell
charmcraft fetch-lib charms.istio_pilot.v0.istio_gateway_info
```
## Using the library as requirer
### Add relation to metadata.yaml
```yaml
requires:
gateway-info:
interface: istio-gateway-info
limit: 1
```
### Instantiate the GatewayRequirer class in charm.py
```python
from ops.charm import CharmBase
from charms.istio_pilot.v0.istio_gateway_info import GatewayRequirer, GatewayRelationError
class RequirerCharm(CharmBase):
def __init__(self, *args):
self.gateway = GatewayRequirer(self)
self.framework.observe(self.on.some_event_emitted, self.some_event_function)
def some_event_function():
# use the getter function wherever the info is needed
try:
gateway_data = self.gateway_relation.get_relation_data()
except GatewayRelationError as error:
"your error handler goes here"
```
## Using the library as provider
### Add relation to metadata.yaml
```yaml
provides:
gateway-info:
interface: istio-gateway-info
```
### Instantiate the GatewayProvider class in charm.py
```python
from ops.charm import CharmBase
from charms.istio_pilot.v0.istio_gateway_info import GatewayProvider, GatewayRelationError
class ProviderCharm(CharmBase):
def __init__(self, *args, **kwargs):
...
self.gateway_provider = GatewayProvider(self)
self.observe(self.on.some_event, self._some_event_handler)
def _some_event_handler(self, ...):
# This will update the relation data bag with the Gateway name and namespace
try:
self.gateway_provider.send_gateway_data(charm, gateway_name, gateway_namespace)
except GatewayRelationError as error:
"your error handler goes here"
```
Note that GatewayProvider.send_gateway_data() sends data to all related applications, and will
execute without error even if no applications are related. If you want to ensure that the someone
is listening for the data, please add checks separately.
## Relation data
The data shared by this library is:
* gateway_name: the name of the Gateway the provider knows about. It corresponds to
the `name` field in the Gateway definition
* gateway_namespace: the namespace where the Gateway is deployed.
* gateway_up: (new in v0.3) boolean indicating whether the Gateway is up. This being True
indicates that the Gateway should be fully established and accepting traffic.
If relating a Requirer of v0.3 to a Provider using v0.2 or earlier of this library, the Requirer
will return gateway_up=True by default.
The following example shows an Istio Gateway with `gateway_name=my-gateway` and
`gateway_namespace=my-gateway-namespace`
```yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: my-gateway
namespace: my-gateway-namespace
```
"""
import logging
from ops.framework import Object
from ops.model import Relation
# The unique Charmhub library identifier, never change it
LIBID = "354103422e7a43e2870e4203fbb5a649"
# Increment this major API version when introducing breaking changes
LIBAPI = 0
# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version
LIBPATCH = 4
# Default relation and interface names. If changed, consistency must be kept
# across the provider and requirer.
DEFAULT_RELATION_NAME = "gateway-info"
DEFAULT_INTERFACE_NAME = "istio-gateway-info"
REQUIRED_ATTRIBUTES = ["gateway_name", "gateway_namespace"]
logger = logging.getLogger(__name__)
class GatewayRelationError(Exception):
pass
class GatewayRelationMissingError(GatewayRelationError):
def __init__(self):
self.message = "Missing gateway-info relation."
super().__init__(self.message)
class GatewayRelationDataMissingError(GatewayRelationError):
def __init__(self, message):
self.message = message
super().__init__(self.message)
class GatewayRequirer(Object):
"""Base class that represents a requirer relation end.
Args:
requirer_charm (CharmBase): the requirer application
relation_name (str, optional): the name of the relation
Attributes:
requirer_charm (CharmBase): variable for storing the requirer application
relation_name (str): variable for storing the name of the relation
"""
def __init__(self, requirer_charm, relation_name: str = DEFAULT_RELATION_NAME):
super().__init__(requirer_charm, relation_name)
# TODO: remove this attribute, we are not really using it at all.
# Leaving it to keep backwards compatibility.
self.requirer_charm = requirer_charm
self.relation_name = relation_name
@staticmethod
def _relation_preflight_checks(relation: Relation) -> None:
"""Series of checks for the relation and relation data.
Args:
relation (Relation): the relation object to run the checks on
Raises:
GatewayRelationDataMissingError: if data is missing or incomplete
GatewayRelationMissingError: if there is no related application
ops.model.TooManyRelatedAppsError: if there is more than one related application
"""
# Raise if there is no related application
if not relation:
raise GatewayRelationMissingError()
# Extract remote app information from relation
remote_app = relation.app
# Get relation data from remote app
relation_data = relation.data[remote_app]
# Raise if there is no data found in the relation data bag
if not relation_data:
raise GatewayRelationDataMissingError("No data found in relation data bag.")
# Check if the relation data contains the expected attributes
missing_attributes = [
attribute for attribute in REQUIRED_ATTRIBUTES if attribute not in relation_data
]
if missing_attributes:
raise GatewayRelationDataMissingError(f"Missing attributes: {missing_attributes}")
def get_relation_data(self) -> dict:
"""Returns a dictionary with the Gateway information.
Raises:
GatewayRelationDataMissingError: if data is missing entirely or some attributes
GatewayRelationMissingError: if there is no related application
"""
# Run pre-flight checks
# Raises TooManyRelatedAppsError if related to more than one app
relation = self.model.get_relation(self.relation_name)
self._relation_preflight_checks(relation=relation)
# Get relation data from remote app
relation_data = relation.data[relation.app]
# Convert string gateway_up back to boolean, defaulting to True if it does not exist.
gateway_up = relation_data.get("gateway_up", "true")
gateway_up = gateway_up.lower() == "true"
return {
"gateway_name": relation_data["gateway_name"],
"gateway_namespace": relation_data["gateway_namespace"],
"gateway_up": gateway_up,
}
class GatewayProvider(Object):
"""Base class that represents a provider relation end.
Args:
provider_charm (CharmBase): the provider application
relation_name (str, optional): the name of the relation
Attributes:
provider_charm (CharmBase): variable for storing the provider application
relation_name (str): variable for storing the name of the relation
"""
def __init__(self, provider_charm, relation_name: str = DEFAULT_RELATION_NAME):
super().__init__(provider_charm, relation_name)
self.provider_charm = provider_charm
self.relation_name = relation_name
def send_gateway_relation_data(
self, gateway_name: str, gateway_namespace: str, gateway_up: bool = True
) -> None:
"""Updates the relation data bag with data from the local gateway.
This method will complete successfully even if there are no related applications.
Args:
gateway_name (str): the name of the Gateway the provider knows about
gateway_namespace(str): the namespace of the Gateway the provider knows about
gateway_up (bool): (optional) the status of the Gateway. Defaults to True if not
provided.
"""
# Update the relation data bag with localgateway information
relations = self.model.relations[self.relation_name]
# Update relation data
for relation in relations:
relation.data[self.provider_charm.app].update(
{
"gateway_name": gateway_name,
"gateway_namespace": gateway_namespace,
"gateway_up": str(gateway_up).lower(),
}
)