resources

package
v0.0.0-...-bb45038 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 26, 2024 License: Apache-2.0 Imports: 76 Imported by: 1

Documentation

Index

Constants

View Source
const (
	ArangoDExecutor                          = "/usr/sbin/arangod"
	ArangoDBOverrideDetectedTotalMemoryEnv   = "ARANGODB_OVERRIDE_DETECTED_TOTAL_MEMORY"
	ArangoDBOverrideDetectedNumberOfCoresEnv = "ARANGODB_OVERRIDE_DETECTED_NUMBER_OF_CORES"
	ArangoDBOverrideServerGroupEnv           = "ARANGODB_OVERRIDE_SERVER_GROUP"
	ArangoDBOverrideDeploymentModeEnv        = "ARANGODB_OVERRIDE_DEPLOYMENT_MODE"
	ArangoDBOverrideVersionEnv               = "ARANGODB_OVERRIDE_VERSION"
	ArangoDBOverrideEnterpriseEnv            = "ARANGODB_OVERRIDE_ENTERPRISE"
	ArangoDBServerPortEnv                    = "ARANGODB_SERVER_PORT"
)
View Source
const (
	CAKeyName  = "ca.key"
	CACertName = "ca.crt"
)
View Source
const (
	ArangoSyncExecutor string = "/usr/sbin/arangosync"
)

Variables

This section is empty.

Functions

func AppendKeyfileToKeyfolder

func AppendKeyfileToKeyfolder(ctx context.Context, cachedStatus inspectorInterface.Inspector,
	secrets secretv1.ModInterface, ownerRef *meta.OwnerReference, secretName string, encryptionKey []byte) error

func ArangodbInternalExporterContainer

func ArangodbInternalExporterContainer(image string, args []string, livenessProbe *probes.HTTPProbeConfig,
	res core.ResourceRequirements, spec api.DeploymentSpec, groupSpec api.ServerGroupSpec) (core.Container, error)

ArangodbInternalExporterContainer creates metrics container based on internal exporter

func ChecksumArangoPod

func ChecksumArangoPod(groupSpec api.ServerGroupSpec, pod *core.Pod) (string, error)

func CreateArangoDVolumes

func CreateArangoDVolumes(status api.MemberStatus, input pod.Input, spec api.DeploymentSpec,
	groupSpec api.ServerGroupSpec) pod.Volumes

CreateArangoDVolumes returns wrapper with volumes for a pod and volume mounts for a container.

func CreateArangoPod

func CreateArangoPod(ctx context.Context, c podv1.ModInterface, deployment k8sutil.APIObject,
	deploymentSpec api.DeploymentSpec, group api.ServerGroup, pod *core.Pod) (string, types.UID, error)

CreateArangoPod creates a new Pod with container provided by parameter 'containerCreator' If the pod already exists, nil is returned. If another error occurs, that error is returned.

func CreatePodFromTemplate

func CreatePodFromTemplate(p *core.PodTemplateSpec) *core.Pod

func CreatePodSuffix

func CreatePodSuffix(spec api.DeploymentSpec) string

CreatePodSuffix creates additional string to glue it to the POD name. The suffix is calculated according to the given spec, so it is easily to recognize by name if the pods have the same spec. The additional `postSuffix` can be provided. It can be used to distinguish restarts of POD.

func CreateServerServicePort

func CreateServerServicePort() core.ServicePort

CreateServerServicePort creates main server service port.

func CreateServerServicePortsWithSidecars

func CreateServerServicePortsWithSidecars(amInspector v1.Inspector, am string) []core.ServicePort

CreateServerServicePortsWithSidecars returns ports for the service.

func GetCASecretName

func GetCASecretName(apiObject k8sutil.APIObject) string

func IsServerProgressAvailable

func IsServerProgressAvailable(group api.ServerGroup, imageInfo api.ImageInfo) bool

IsServerProgressAvailable returns true if server progress is available.

func LabelsForExporterServiceMonitor

func LabelsForExporterServiceMonitor(name string, obj deploymentApi.DeploymentSpec) map[string]string

func LabelsForExporterServiceMonitorSelector

func LabelsForExporterServiceMonitorSelector(name string) map[string]string

func PDBNameForGroup

func PDBNameForGroup(depl string, group api.ServerGroup) string

func RenderArangoPod

func RenderArangoPod(ctx context.Context, cachedStatus inspectorInterface.Inspector, deployment k8sutil.APIObject,
	role, id, podName string, podCreator interfaces.PodCreator) (*core.Pod, error)

RenderArangoPod renders new ArangoD Pod

Types

type ArangoDContainer

type ArangoDContainer struct {
	// contains filtered or unexported fields
}

func (*ArangoDContainer) GetCommand

func (a *ArangoDContainer) GetCommand() ([]string, error)

func (*ArangoDContainer) GetEnvs

func (a *ArangoDContainer) GetEnvs() ([]core.EnvVar, []core.EnvFromSource)

GetEnvs returns environment variables for ArangoDB containers.

func (*ArangoDContainer) GetExecutor

func (a *ArangoDContainer) GetExecutor() string

func (*ArangoDContainer) GetImage

func (a *ArangoDContainer) GetImage() string

func (*ArangoDContainer) GetImagePullPolicy

func (a *ArangoDContainer) GetImagePullPolicy() core.PullPolicy

func (*ArangoDContainer) GetLifecycle

func (a *ArangoDContainer) GetLifecycle() (*core.Lifecycle, error)

func (*ArangoDContainer) GetName

func (a *ArangoDContainer) GetName() string

func (*ArangoDContainer) GetPorts

func (a *ArangoDContainer) GetPorts() []core.ContainerPort

func (*ArangoDContainer) GetProbes

func (a *ArangoDContainer) GetProbes() (*core.Probe, *core.Probe, *core.Probe, error)

func (*ArangoDContainer) GetResourceRequirements

func (a *ArangoDContainer) GetResourceRequirements() core.ResourceRequirements

func (*ArangoDContainer) GetSecurityContext

func (a *ArangoDContainer) GetSecurityContext() *core.SecurityContext

func (*ArangoDContainer) GetVolumeMounts

func (a *ArangoDContainer) GetVolumeMounts() []core.VolumeMount

type ArangoSyncContainer

type ArangoSyncContainer struct {
	// contains filtered or unexported fields
}

func (*ArangoSyncContainer) GetCommand

func (a *ArangoSyncContainer) GetCommand() ([]string, error)

func (*ArangoSyncContainer) GetEnvs

func (a *ArangoSyncContainer) GetEnvs() ([]core.EnvVar, []core.EnvFromSource)

func (*ArangoSyncContainer) GetExecutor

func (a *ArangoSyncContainer) GetExecutor() string

func (*ArangoSyncContainer) GetImage

func (a *ArangoSyncContainer) GetImage() string

func (*ArangoSyncContainer) GetImagePullPolicy

func (a *ArangoSyncContainer) GetImagePullPolicy() core.PullPolicy

func (*ArangoSyncContainer) GetLifecycle

func (a *ArangoSyncContainer) GetLifecycle() (*core.Lifecycle, error)

func (*ArangoSyncContainer) GetName

func (a *ArangoSyncContainer) GetName() string

func (*ArangoSyncContainer) GetPorts

func (a *ArangoSyncContainer) GetPorts() []core.ContainerPort

func (*ArangoSyncContainer) GetProbes

func (a *ArangoSyncContainer) GetProbes() (*core.Probe, *core.Probe, *core.Probe, error)

func (*ArangoSyncContainer) GetResourceRequirements

func (a *ArangoSyncContainer) GetResourceRequirements() core.ResourceRequirements

func (*ArangoSyncContainer) GetSecurityContext

func (a *ArangoSyncContainer) GetSecurityContext() *core.SecurityContext

func (*ArangoSyncContainer) GetVolumeMounts

func (a *ArangoSyncContainer) GetVolumeMounts() []core.VolumeMount

type ArangoUpgradeContainer

type ArangoUpgradeContainer struct {
	interfaces.ContainerCreator
	// contains filtered or unexported fields
}

ArangoUpgradeContainer can construct ArangoD upgrade container.

func (*ArangoUpgradeContainer) GetCommand

func (a *ArangoUpgradeContainer) GetCommand() ([]string, error)

GetCommand returns list of arguments for the ArangoD upgrade container.

func (*ArangoUpgradeContainer) GetLifecycle

func (a *ArangoUpgradeContainer) GetLifecycle() (*core.Lifecycle, error)

GetLifecycle returns no lifecycle for the ArangoD upgrade container.

func (*ArangoUpgradeContainer) GetName

func (a *ArangoUpgradeContainer) GetName() string

GetName returns the name of the ArangoD upgrade container.

func (*ArangoUpgradeContainer) GetProbes

func (a *ArangoUpgradeContainer) GetProbes() (*core.Probe, *core.Probe, *core.Probe, error)

GetProbes returns no probes for the ArangoD upgrade container.

type ArangoVersionCheckContainer

type ArangoVersionCheckContainer struct {
	interfaces.ContainerCreator
	// contains filtered or unexported fields
}

ArangoVersionCheckContainer can construct ArangoD version check container.

func (*ArangoVersionCheckContainer) GetCommand

func (a *ArangoVersionCheckContainer) GetCommand() ([]string, error)

GetCommand returns list of arguments for the ArangoD version check container.

func (*ArangoVersionCheckContainer) GetLifecycle

func (a *ArangoVersionCheckContainer) GetLifecycle() (*core.Lifecycle, error)

GetLifecycle returns no lifecycle for the ArangoD version check container.

func (*ArangoVersionCheckContainer) GetName

func (a *ArangoVersionCheckContainer) GetName() string

GetName returns the name of the ArangoD version check container.

func (*ArangoVersionCheckContainer) GetProbes

GetProbes returns no probes for the ArangoD version check container.

type Context

type Context interface {
	reconciler.DeploymentStatusUpdate
	reconciler.DeploymentAgencyMaintenance
	reconciler.DeploymentImageManager
	reconciler.ArangoAgency
	reconciler.ArangoApplier
	reconciler.DeploymentGetter
	reconciler.KubernetesEventGenerator

	member.StateInspectorGetter

	sutil.ACSGetter

	// GetServerGroupIterator returns the deployment as ServerGroupIterator.
	GetServerGroupIterator() reconciler.ServerGroupIterator
	// GetOperatorImage returns the image name of operator image
	GetOperatorImage() string
	// CreateEvent creates a given event.
	// On error, the error is logged.
	CreateEvent(evt *k8sutil.Event)
	// GetOwnedPVCs returns a list of all PVCs owned by the deployment.
	GetOwnedPVCs() ([]core.PersistentVolumeClaim, error)
	// GetBackup receives information about a backup resource
	GetBackup(ctx context.Context, backup string) (*backupApi.ArangoBackup, error)
	GetScope() scope.Scope
}

Context provides all functions needed by the Resources service to perform its service.

type EnvBuilder

type EnvBuilder []core.EnvVar

EnvBuilder build environment variables

func NewEnvBuilder

func NewEnvBuilder() EnvBuilder

NewEnvBuilder creates new ENV builder

func (*EnvBuilder) Add

func (e *EnvBuilder) Add(override bool, envs ...core.EnvVar) (modified bool)

Add append or override flag in envs. Flag is value was modified is returned

func (EnvBuilder) GetEnvList

func (e EnvBuilder) GetEnvList() []core.EnvVar

GetEnvList return copy of env list

type MemberArangoDPod

type MemberArangoDPod struct {
	// contains filtered or unexported fields
}

func (*MemberArangoDPod) Annotations

func (m *MemberArangoDPod) Annotations() map[string]string

func (*MemberArangoDPod) ApplyPodSpec

func (m *MemberArangoDPod) ApplyPodSpec(p *core.PodSpec) error

func (*MemberArangoDPod) AsInput

func (m *MemberArangoDPod) AsInput() pod.Input

func (*MemberArangoDPod) GetContainerCreator

func (m *MemberArangoDPod) GetContainerCreator() interfaces.ContainerCreator

func (*MemberArangoDPod) GetFinalizers

func (m *MemberArangoDPod) GetFinalizers() []string

func (*MemberArangoDPod) GetImagePullSecrets

func (m *MemberArangoDPod) GetImagePullSecrets() []string

func (*MemberArangoDPod) GetInitContainers

func (m *MemberArangoDPod) GetInitContainers(cachedStatus interfaces.Inspector) ([]core.Container, error)

func (*MemberArangoDPod) GetName

func (m *MemberArangoDPod) GetName() string

func (*MemberArangoDPod) GetNodeAffinity

func (m *MemberArangoDPod) GetNodeAffinity() *core.NodeAffinity

func (*MemberArangoDPod) GetNodeSelector

func (m *MemberArangoDPod) GetNodeSelector() map[string]string

func (*MemberArangoDPod) GetPodAffinity

func (m *MemberArangoDPod) GetPodAffinity() *core.PodAffinity

func (*MemberArangoDPod) GetPodAntiAffinity

func (m *MemberArangoDPod) GetPodAntiAffinity() *core.PodAntiAffinity

func (*MemberArangoDPod) GetRestartPolicy

func (m *MemberArangoDPod) GetRestartPolicy() core.RestartPolicy

func (*MemberArangoDPod) GetRole

func (m *MemberArangoDPod) GetRole() string

func (*MemberArangoDPod) GetServiceAccountName

func (m *MemberArangoDPod) GetServiceAccountName() string

func (*MemberArangoDPod) GetSidecars

func (m *MemberArangoDPod) GetSidecars(pod *core.Pod) error

func (*MemberArangoDPod) GetTolerations

func (m *MemberArangoDPod) GetTolerations() []core.Toleration

func (*MemberArangoDPod) GetVolumes

func (m *MemberArangoDPod) GetVolumes() []core.Volume

func (*MemberArangoDPod) Init

func (*MemberArangoDPod) IsDeploymentMode

func (m *MemberArangoDPod) IsDeploymentMode() bool

func (*MemberArangoDPod) Labels

func (m *MemberArangoDPod) Labels() map[string]string

func (*MemberArangoDPod) Validate

func (m *MemberArangoDPod) Validate(cachedStatus interfaces.Inspector) error

type MemberSyncPod

type MemberSyncPod struct {
	// contains filtered or unexported fields
}

func (*MemberSyncPod) Annotations

func (m *MemberSyncPod) Annotations() map[string]string

func (*MemberSyncPod) ApplyPodSpec

func (m *MemberSyncPod) ApplyPodSpec(spec *core.PodSpec) error

func (*MemberSyncPod) GetContainerCreator

func (m *MemberSyncPod) GetContainerCreator() interfaces.ContainerCreator

func (*MemberSyncPod) GetFinalizers

func (m *MemberSyncPod) GetFinalizers() []string

func (*MemberSyncPod) GetImagePullSecrets

func (m *MemberSyncPod) GetImagePullSecrets() []string

func (*MemberSyncPod) GetInitContainers

func (m *MemberSyncPod) GetInitContainers(cachedStatus interfaces.Inspector) ([]core.Container, error)

func (*MemberSyncPod) GetName

func (m *MemberSyncPod) GetName() string

func (*MemberSyncPod) GetNodeAffinity

func (m *MemberSyncPod) GetNodeAffinity() *core.NodeAffinity

func (*MemberSyncPod) GetNodeSelector

func (m *MemberSyncPod) GetNodeSelector() map[string]string

func (*MemberSyncPod) GetPodAffinity

func (m *MemberSyncPod) GetPodAffinity() *core.PodAffinity

func (*MemberSyncPod) GetPodAntiAffinity

func (m *MemberSyncPod) GetPodAntiAffinity() *core.PodAntiAffinity

func (*MemberSyncPod) GetRestartPolicy

func (m *MemberSyncPod) GetRestartPolicy() core.RestartPolicy

func (*MemberSyncPod) GetRole

func (m *MemberSyncPod) GetRole() string

func (*MemberSyncPod) GetServiceAccountName

func (m *MemberSyncPod) GetServiceAccountName() string

func (*MemberSyncPod) GetSidecars

func (m *MemberSyncPod) GetSidecars(pod *core.Pod) error

func (*MemberSyncPod) GetTolerations

func (m *MemberSyncPod) GetTolerations() []core.Toleration

func (*MemberSyncPod) GetVolumes

func (m *MemberSyncPod) GetVolumes() []core.Volume

GetVolumes returns volumes for the ArangoSync container.

func (*MemberSyncPod) Init

func (m *MemberSyncPod) Init(ctx context.Context, cachedStatus interfaces.Inspector, pod *core.Pod) error

Init initializes the arangosync pod.

func (*MemberSyncPod) IsDeploymentMode

func (m *MemberSyncPod) IsDeploymentMode() bool

func (*MemberSyncPod) Labels

func (m *MemberSyncPod) Labels() map[string]string

func (*MemberSyncPod) Validate

func (m *MemberSyncPod) Validate(_ interfaces.Inspector) error

type MetricContainerRestarts

type MetricContainerRestarts map[string]MetricMemberRestarts

type MetricMember

type MetricMember struct {
	ContainerRestarts          MetricContainerRestarts
	InitContainerRestarts      MetricContainerRestarts
	EphemeralContainerRestarts MetricContainerRestarts
}

type MetricMemberRestartReason

type MetricMemberRestartReason map[string]uint64

type MetricMemberRestarts

type MetricMemberRestarts map[int32]MetricMemberRestartReason

type Metrics

type Metrics struct {
	Members map[string]MetricMember
	// contains filtered or unexported fields
}

func (*Metrics) IncMemberContainerRestarts

func (m *Metrics) IncMemberContainerRestarts(id, container, reason string, code int32)

func (*Metrics) IncMemberEphemeralContainerRestarts

func (m *Metrics) IncMemberEphemeralContainerRestarts(id, container, reason string, code int32)

func (*Metrics) IncMemberInitContainerRestarts

func (m *Metrics) IncMemberInitContainerRestarts(id, container, reason string, code int32)

type PatchFunc

type PatchFunc func(name string, d []byte) error

type Probe

type Probe interface {
	Create() *core.Probe

	SetSpec(spec *api.ServerGroupProbeSpec)
}

type Resources

type Resources struct {
	// contains filtered or unexported fields
}

Resources is a service that creates low level resources for members and inspects low level resources, put the inspection result in members.

func NewResources

func NewResources(namespace, name string, context Context) *Resources

NewResources creates a new Resources service, used to create and inspect low level resources such as pods and services.

func (*Resources) CleanupTerminatedPods

func (r *Resources) CleanupTerminatedPods(ctx context.Context) (util.Interval, error)

CleanupTerminatedPods removes all pods in Terminated state that belong to a member in Created state. Returns: Interval_till_next_inspection, error

func (*Resources) CollectMetrics

func (r *Resources) CollectMetrics(m metrics.PushMetric)

func (*Resources) CreatePodTolerations

func (r *Resources) CreatePodTolerations(group api.ServerGroup, groupSpec api.ServerGroupSpec) []core.Toleration

CreatePodTolerations creates a list of tolerations for a pod created for the given group.

func (*Resources) EnsureAnnotations

func (r *Resources) EnsureAnnotations(ctx context.Context, cachedStatus inspectorInterface.Inspector) error

func (*Resources) EnsureArangoMembers

func (r *Resources) EnsureArangoMembers(ctx context.Context, cachedStatus inspectorInterface.Inspector) error

func (*Resources) EnsureCoreResources

func (r *Resources) EnsureCoreResources(ctx context.Context, cachedStatus inspectorInterface.Inspector) error

func (*Resources) EnsureLabels

func (r *Resources) EnsureLabels(ctx context.Context, cachedStatus inspectorInterface.Inspector) error

func (*Resources) EnsureLeader

func (r *Resources) EnsureLeader(ctx context.Context, cachedStatus inspectorInterface.Inspector) error

EnsureLeader creates leader label on the pod's agency and creates service to it. When agency leader is not known then all agencies' pods should not have leader label, and consequentially service will not point to any pod. It works only in active fail-over mode.

func (*Resources) EnsurePDBs

func (r *Resources) EnsurePDBs(ctx context.Context) error

EnsurePDBs ensures Pod Disruption Budgets for different server groups in Cluster mode

func (*Resources) EnsurePVCs

func (r *Resources) EnsurePVCs(ctx context.Context, cachedStatus inspectorInterface.Inspector) error

EnsurePVCs creates all PVC's listed in member status

func (*Resources) EnsurePersistentVolumeClaimsLabels

func (r *Resources) EnsurePersistentVolumeClaimsLabels(ctx context.Context, cachedStatus inspectorInterface.Inspector) error

func (*Resources) EnsurePodDisruptionBudgetsLabels

func (r *Resources) EnsurePodDisruptionBudgetsLabels(ctx context.Context, cachedStatus inspectorInterface.Inspector) error

func (*Resources) EnsurePods

func (r *Resources) EnsurePods(ctx context.Context, cachedStatus inspectorInterface.Inspector) error

EnsurePods creates all Pods listed in member status

func (*Resources) EnsurePodsLabels

func (r *Resources) EnsurePodsLabels(ctx context.Context, cachedStatus inspectorInterface.Inspector) error

func (*Resources) EnsureResources

func (r *Resources) EnsureResources(ctx context.Context, serviceMonitorEnabled bool, cachedStatus inspectorInterface.Inspector) error

func (*Resources) EnsureSecretLabels

func (r *Resources) EnsureSecretLabels(ctx context.Context, cachedStatus inspectorInterface.Inspector) error

func (*Resources) EnsureSecrets

func (r *Resources) EnsureSecrets(ctx context.Context, cachedStatus inspectorInterface.Inspector) error

EnsureSecrets creates all secrets needed to run the given deployment

func (*Resources) EnsureServiceAccountsLabels

func (r *Resources) EnsureServiceAccountsLabels(ctx context.Context, cachedStatus inspectorInterface.Inspector) error

func (*Resources) EnsureServiceMonitor

func (r *Resources) EnsureServiceMonitor(ctx context.Context, enabled bool) error

EnsureServiceMonitor creates or updates a ServiceMonitor.

func (*Resources) EnsureServiceMonitorsLabels

func (r *Resources) EnsureServiceMonitorsLabels(ctx context.Context, cachedStatus inspectorInterface.Inspector) error

func (*Resources) EnsureServices

func (r *Resources) EnsureServices(ctx context.Context, cachedStatus inspectorInterface.Inspector) error

EnsureServices creates all services needed to service the deployment

func (*Resources) EnsureServicesLabels

func (r *Resources) EnsureServicesLabels(ctx context.Context, cachedStatus inspectorInterface.Inspector) error

func (*Resources) GetCertsFromData

func (r *Resources) GetCertsFromData(caPem []byte) crypto.Certificates

func (*Resources) GetCertsFromSecret

func (r *Resources) GetCertsFromSecret(secret *core.Secret) crypto.Certificates

func (*Resources) InspectPVCs

func (r *Resources) InspectPVCs(ctx context.Context, cachedStatus inspectorInterface.Inspector) (util.Interval, error)

InspectPVCs lists all PVCs that belong to the given deployment and updates the member status of the deployment accordingly.

func (*Resources) InspectPods

func (r *Resources) InspectPods(ctx context.Context, cachedStatus inspectorInterface.Inspector) (util.Interval, error)

InspectPods lists all pods that belong to the given deployment and updates the member status of the deployment accordingly. Returns: Interval_till_next_inspection, error

func (*Resources) RenderPodForMember

func (r *Resources) RenderPodForMember(ctx context.Context, acs sutil.ACS, spec api.DeploymentSpec, status api.DeploymentStatus, memberID string, imageInfo api.ImageInfo) (*core.Pod, error)

func (*Resources) RenderPodTemplateForMember

func (r *Resources) RenderPodTemplateForMember(ctx context.Context, acs sutil.ACS, spec api.DeploymentSpec, status api.DeploymentStatus, memberID string, imageInfo api.ImageInfo) (*core.PodTemplateSpec, error)

func (*Resources) SelectImage

func (r *Resources) SelectImage(spec api.DeploymentSpec, status api.DeploymentStatus) (api.ImageInfo, bool)

func (*Resources) SelectImageForMember

func (r *Resources) SelectImageForMember(spec api.DeploymentSpec, status api.DeploymentStatus, member api.MemberStatus) (api.ImageInfo, bool)

func (*Resources) SyncMembersInCluster

func (r *Resources) SyncMembersInCluster(ctx context.Context, health memberState.Health) error

SyncMembersInCluster sets proper condition for all arangod members that belongs to the deployment.

func (*Resources) ValidateSecretHashes

func (r *Resources) ValidateSecretHashes(ctx context.Context, cachedStatus inspectorInterface.Inspector) error

ValidateSecretHashes checks the hash of used secrets against the stored ones. If a hash is different, the deployment is marked with a SecretChangedCondition and the operator will not touch it until this is resolved.

func (*Resources) WrapLogger

func (r *Resources) WrapLogger(in *zerolog.Event) *zerolog.Event

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL