service

Service module.

exception spicerack.service.DiscoveryRecordNotFoundError[source]

Bases: ServiceError

Exception class raised when a DNS Discovery record is not found by name or there is none.

exception spicerack.service.DiscoveryStateError[source]

Bases: ServiceError

Exception class raised when a dns discovery record does not correspond to its conftool state.

exception spicerack.service.ServiceError[source]

Bases: SpicerackError

Generic exception class for errors in the service module.

exception spicerack.service.ServiceNotFoundError[source]

Bases: ServiceError

Exception class raised when a service is not found.

exception spicerack.service.TooManyDiscoveryRecordsError[source]

Bases: ServiceError

Exception class raised when more than one DNS Discovery record is present but not name was specified.

class spicerack.service.Catalog(catalog: dict, *, alertmanager: spicerack.alertmanager.Alertmanager, confctl: spicerack.confctl.ConftoolEntity, authdns_servers: dict[str, str], dry_run: bool = True)[source]

Bases: object

Class to represent the service catalog of Puppet's hierdata service::catalog.

The catalog behaves like an Iterator, so it can be iterated in list-comprehension and similar contructs. It supports also len(), to quickly know how many services are loaded in the catalog.

Examples

Get all service that are present in a given datacenter:

>>> esams = [service for service in catalog if "esams" in service.sites]

See how many services are configured:

>>> num_services = len(catalog)

Initialize the instance.

Parameters:
  • catalog (dict) -- the content of Puppet's hieradata/common/service.yaml.

  • alertmanager (spicerack.alertmanager.Alertmanager) -- the alertmanager instance to interact with.

  • confctl (spicerack.confctl.ConftoolEntity) -- the instance to interact with confctl.

  • authdns_servers (dict[str, str]) -- a dictionary where keys are the hostnames and values are the IPs of the authoritative nameservers to be used.

  • dry_run (bool, default: True) -- whether this is a DRY-RUN.

get(name: str) spicerack.service.Service[source]

Get a single service by name.

Examples

Get a specific service:

>>> service = catalog.get("service_name")
Parameters:

name (str) -- the service name.

Raises:

spicerack.service.ServiceNotFoundError -- if the service is not found.

Return type:

spicerack.service.Service

property service_names: list[str]

Get all defined service names.

class spicerack.service.Service(name: str, description: str, encryption: bool, ip: spicerack.service.ServiceIPs, port: int, sites: list[str], state: str, _dry_run: bool, _alertmanager: spicerack.alertmanager.AlertmanagerHosts, aliases: list[str] = <factory>, discovery: spicerack.service.ServiceDiscovery | None = None, httpbb_dir: str = '', lvs: spicerack.service.ServiceLVS | None = None, monitoring: spicerack.service.ServiceMonitoring | None = None, page: bool = True, probes: list[dict] = <factory>, public_aliases: list[str] = <factory>, public_endpoint: str = '', role: str = '') None[source]

Bases: object

Class to represent a service as defined in Puppet's service::catalog hieradata.

See also

Puppet's modules/wmflib/types/service.pp.

Parameters:
  • name (str) -- the service name.

  • description (str) -- the service description.

  • encryption (bool) -- whether TLS encryption is enabled or not on the service.

  • ip (spicerack.service.ServiceIPs) -- the instance that represents all the service IPs.

  • port (int) -- the port the service listen on.

  • sites (list[str]) -- the list of datacenters where the service is configured.

  • state (str) -- the production state of the service (e.g. lvs_setup).

  • _alertmanager (spicerack.alertmanager.AlertmanagerHosts) -- the AlertmanagerHosts instance to perform downtime.

  • aliases (list[str], default: <factory>) -- a list of aliases names for the service.

  • discovery (typing.Optional[spicerack.service.ServiceDiscovery], default: None) -- the collection of spicerack.service.ServiceDiscoveryRecord instances reprensenting the DNS Discovery capabilities of the service.

  • lvs (typing.Optional[spicerack.service.ServiceLVS], default: None) -- the load balancer configuration.

  • monitoring (typing.Optional[spicerack.service.ServiceMonitoring], default: None) -- the service monitoring configuration.

  • page (bool, default: True) -- whether the monitoring for this service does page or not.

  • probes (list[dict], default: <factory>) -- a list of probe dictionaries with all the parameters necessary to define the probes for this service.

  • public_aliases (list[str], default: <factory>) -- the list of public aliases set for this service.

  • public_endpoint (str, default: '') -- the name of the public endpoint if present, empty string otherwise.

  • role (str, default: '') -- the service role name in Puppet if present, empty string otherwise.

check_dns_state(ip_per_dc_map: dict[str, ipaddress.IPv4Address | ipaddress.IPv6Address], record_name: str = '', tries: int = 15) None[source]

Checks the state of dns discovery is consistent.

Checks that a discovery record state on the dns servers corresponds to the state in the conftool discovery backend.

Parameters:
  • ip_per_dc_map (dict[str, typing.Union[ipaddress.IPv4Address, ipaddress.IPv6Address]]) -- mapping of datacenter -> client IP to use.

  • record_name (str, default: '') -- the discovery record name to inspect. If left empty, it will pick up the only discovery record.

  • tries (int, default: 15) -- the number of retries to attempt before failing.

Raises:
Return type:

None

downtime(site: str, reason: spicerack.administrative.Reason, *, duration: datetime.timedelta = datetime.timedelta(seconds=14400)) str[source]

Downtime the service on the given site in Alertmanager and return its ID.

Parameters:
Raises:

spicerack.service.ServiceError -- if the service is not present in the given datacenter.

Return type:

str

downtimed(site: str, reason: spicerack.administrative.Reason, *, duration: datetime.timedelta = datetime.timedelta(seconds=14400), remove_on_error: bool = False) collections.abc.Iterator[None][source]

Context manager to perform actions while the service is downtimed in the given site in Alertmanager.

Parameters:
  • site (str) -- the datacenter where to silence the service.

  • reason (spicerack.administrative.Reason) -- the silence reason.

  • duration (datetime.timedelta, default: datetime.timedelta(seconds=14400)) -- how long to silence for.

  • remove_on_error (bool, default: False) -- should the downtime be removed even if an exception was raised.

Raises:

spicerack.service.ServiceError -- if the service is not present in the given datacenter.

Return type:

collections.abc.Iterator[None]

class spicerack.service.ServiceDiscovery(records: collections.abc.Sequence[spicerack.service.ServiceDiscoveryRecord])[source]

Bases: Iterable

Represents the service Discovery records collection as list-like object with helper methods.

The discovery behaves like an Iterator, so it can be iterated in list-comprehension and similar contructs. It supports also len(), to quickly know how many records are configured for the service.

Initialize the instance with the records.

Parameters:

records (collections.abc.Sequence[spicerack.service.ServiceDiscoveryRecord]) -- the DNS Discovery records.

depool(site: str, *, name: str = '') None[source]

Depool the service from the given site in DNS Discovery.

Parameters:
  • site (str) -- the datacenter to depool the service from.

  • name (str, default: '') -- the dnsdisc name of the DNS Discovery record to depool. If empty, and there is only one record, it will depool that one.

Raises:
Return type:

None

depooled(site: str, *, name: str = '', repool_on_error: bool = False) collections.abc.Iterator[None][source]

Context manager to act while the service is depooled from the given site in DNS Discovery.

It will not repool the service on the given site if any exception is raised within the context manager context, unless repool_on_error is set to True.

Parameters:
  • site (str) -- the datacenter to depool the service from.

  • name (str, default: '') -- the dnsdisc name of the DNS Discovery record to depool. If empty, and there is only one record, it will depool that one.

  • repool_on_error (bool, default: False) -- whether to repool the site on error or not.

Yields:

None -- it just gives back control to the caller.

Raises:
Return type:

collections.abc.Iterator[None]

get(name: str = '') spicerack.service.ServiceDiscoveryRecord[source]

Return the DNS Discovery record for the given name, raise an exception if not found.

Parameters:

name (str, default: '') -- the dnsdic name of the DNS Discovery record. If set to an empty string, and the service has only one service, it will return that one.

Raises:
Return type:

spicerack.service.ServiceDiscoveryRecord

pool(site: str, *, name: str = '') None[source]

Pool the service to the given site in DNS Discovery.

Parameters:
  • site (str) -- the datacenter to pool the service to.

  • name (str, default: '') -- the dnsdisc name of the DNS Discovery record to pool. If empty, and there is only one record, it will pool that one.

Raises:
Return type:

None

class spicerack.service.ServiceDiscoveryRecord(active_active: bool, dnsdisc: str, instance: spicerack.dnsdisc.Discovery) None[source]

Bases: object

Represents the DNS Discovery attributes of the service.

See also

Puppet's modules/wmflib/types/service/discovery.pp.

Parameters:
  • active_active (bool) -- True if the service is active/active in DNS Discovery.

  • dnsdisc (str) -- the name used in conftool for the discovery record.

  • instance (spicerack.dnsdisc.Discovery) -- the DNS Discovery intance to operate on the service.

check_service_ips(service_ips: spicerack.service.ServiceIPs, ip_per_dc_map: dict[str, ipaddress.IPv4Address | ipaddress.IPv6Address]) None[source]

Check the DNS records.

For every datacenter the service is present in, we check that: * If the datacenter is pooled, resolving the name from a client in that datacenter returns the local IP of the service * If it's depooled, resolving the name from a client in that datacenter returns a non-local ip for the service.

The most important function of this check is to ensure the etcd change has been propagated before we cleare the dns recursor caches.

Parameters:
Raises:

spicerack.serviceDiscoveryStateError -- on failure.

Return type:

None

is_pooled_in(datacenter: str) bool[source]

True if the dnsdisc object is pooled in the datacenter.

Return type:

bool

property fqdn: str

The fqdn of the record.

property state: set[str]

The state of the dnsdisc object.

Returns a set with the names of the datacenters where the record is pooled.

class spicerack.service.ServiceIPs(data: dict[str, dict[str, str]]) None[source]

Bases: object

Represent the service IPs.

See also

Puppet's modules/wmflib/types/service/ipblock.pp.

Parameters:

data (dict[str, dict[str, str]]) -- a dictionary representing the service IPs data as defined in service::catalog.

get(site: str, label: str = 'default') ipaddress.IPv4Address | ipaddress.IPv6Address | None[source]

Get the IP for a given datacenter and optional label.

Parameters:
  • site (str) -- the datacenter to filter for.

  • label (str, default: 'default') -- the label of the IP.

Returns:

if the matched IP is an IPv4. ipaddress.IPv6Address: if the matched IP is an IPv6. None: if there is no IP matching the criteria.

Return type:

ipaddress.IPv4Address

property all: list[IPv4Address | IPv6Address]

Return all the service IPs.

property sites: list[str]

Returns all the datacenters where there is at least one IP for the service.

class spicerack.service.ServiceLVS(conftool: spicerack.service.ServiceLVSConftool, depool_threshold: str, enabled: bool, lvs_class: str, monitors: dict[str, dict] | None = None, bgp: bool = True, protocol: str = 'tcp', scheduler: str = 'wrr', ipip_encapsulation: bool = False) None[source]

Bases: object

Represent the load balancer configuration for the service.

See also

Puppet's modules/wmflib/types/service/lvs.pp.

Parameters:
  • conftool (spicerack.service.ServiceLVSConftool) -- the conftool configuration for the service.

  • depool_threshold (str) -- the percentage of the cluster that Pybal will keep pooled anyway on failure.

  • enabled (bool) -- whether the service is enabled on the load balancers.

  • lvs_class (str) -- the traffic class of the service (e.g. low-traffic).

  • monitors (typing.Optional[dict[str, dict]], default: None) -- a dictionary of Pybal monitors configured for the service.

  • bgp (bool, default: True) -- whether Pybal advertise the service via BGP or not.

  • protocol (str, default: 'tcp') -- the Internet protocol of the service.

  • scheduler (str, default: 'wrr') -- the IPVS scheduler used for the service.

  • ipip_encapsulation (bool, default: False) -- Whether the realservers receive traffic from the load balancers using IPIP encapsulation

class spicerack.service.ServiceLVSConftool(cluster: str, service: str) None[source]

Bases: object

Represent the conftool configuration for the service for the load balancers.

Parameters:
  • cluster (str) -- name of the cluster tag in conftool.

  • service (str) -- name of the service tag in conftool.

class spicerack.service.ServiceMonitoring(check_command: str, sites: spicerack.service.ServiceMonitoringHostnames, contact_group: str = '', notes_url: str = '') None[source]

Bases: object

Represent the monitoring configuration for the service.

See also

Puppet's modules/wmflib/types/service/monitoring.pp.

Parameters:
  • check_command (str) -- the Icinga check command used to monitor the service.

  • sites (spicerack.service.ServiceMonitoringHostnames) -- the FQDNs used to monitor the service in each datacenter.

  • contact_group (str, default: '') -- the name of the Icinga contact group used for the service.

  • notes_url (str, default: '') -- the Icinga notes URL pointing to the service runbook.

class spicerack.service.ServiceMonitoringHostnames(data: dict[str, dict[str, str]]) None[source]

Bases: object

Represent the Icinga hostnames or FQDNs used to monitor the service in each datacenter.

See also

Puppet's modules/wmflib/types/service/monitoring.pp.

Parameters:

data (dict[str, dict[str, str]]) -- the service monitoring dictionary.

get(site: str) str[source]

Get the monitoring hostname/FQDN for the service in the given datacenter, empty string if not configured.

Return type:

str

property all: list[str]

Return all service monitoring Icinga hostnames/FQDNs.

property sites: list[str]

Return all the datacenters in which the monitoring is configured for.