engineapi

package
v1.2.5-rc1 Latest Latest
Warning

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

Go to latest
Published: Aug 19, 2022 License: Apache-2.0 Imports: 24 Imported by: 0

Documentation

Index

Constants

View Source
const (
	BackingImageManagerDefaultPort = 8000

	CurrentBackingImageManagerAPIVersion = 2
	MinBackingImageManagerAPIVersion     = 2
	UnknownBackingImageManagerAPIVersion = 0
)
View Source
const (
	BackupMonitorSyncPeriod = 2 * time.Second

	// BackupMonitorMaxRetryPeriod is the maximum retry period when backup monitor routine
	// encounters an error and backup stays in Pending state
	BackupMonitorMaxRetryPeriod = 24 * time.Hour
)
View Source
const (
	ProcessStateInProgress = "in_progress"
	ProcessStateComplete   = "complete"
	ProcessStateError      = "error"
)

Should be the same values as in https://github.com/longhorn/longhorn-engine/blob/master/pkg/types/types.go

View Source
const (
	CurrentInstanceManagerAPIVersion = 1
	UnknownInstanceManagerAPIVersion = 0

	DefaultEnginePortCount  = 1
	DefaultReplicaPortCount = 15

	DefaultPortArg         = "--listen,0.0.0.0:"
	DefaultTerminateSignal = "SIGHUP"

	// IncompatibleInstanceManagerAPIVersion means the instance manager version in v0.7.0
	IncompatibleInstanceManagerAPIVersion = -1
	DeprecatedInstanceManagerBinaryName   = "longhorn-instance-manager"
)
View Source
const (
	// CurrentCLIVersion indicates the default API version manager used to talk with the
	// engine, including `longhorn-engine` and `longhorn-instance-manager`
	CurrentCLIVersion = 5
	// MinCLIVersion indicates the Min API version manager used to talk with the
	// engine.
	MinCLIVersion = 3

	CLIVersionFour = 4
	CLIVersionFive = 5

	InstanceManagerDefaultPort = 8500

	DefaultISCSIPort = "3260"
	DefaultISCSILUN  = "1"

	MaxPollCount = 60
	MinPollCount = 1
	PollInterval = 1 * time.Second

	BackingImageDataSourcePollInterval = 3 * PollInterval

	MaxMonitorRetryCount = 10
)
View Source
const (
	BackingImageDataSourceDefaultPort = 8001
)
View Source
const (
	VolumeHeadName = "volume-head"
)

Variables

This section is empty.

Functions

func CheckBackingImageManagerCompatibilty added in v1.1.1

func CheckBackingImageManagerCompatibilty(bimMinVersion, bimVersion int) error

func CheckCLICompatibilty

func CheckCLICompatibilty(cliVersion, cliMinVersion int) error

func CheckInstanceManagerCompatibilty added in v0.8.0

func CheckInstanceManagerCompatibilty(imMinVersion, imVersion int) error

func ConvertEngineBackupState added in v1.2.3

func ConvertEngineBackupState(state string) longhorn.BackupState

ConvertEngineBackupState converts longhorn engine backup state to Backup CR state

func GetAddressFromBackendReplicaURL added in v0.6.0

func GetAddressFromBackendReplicaURL(url string) string

func GetBackendReplicaURL added in v0.6.0

func GetBackendReplicaURL(address string) string

func GetBackingImageDataSourceFileName added in v1.2.0

func GetBackingImageDataSourceFileName(bidsName, biUUID string) string

func GetDeprecatedInstanceManagerBinary added in v0.8.0

func GetDeprecatedInstanceManagerBinary(image string) string

func GetEngineEndpoint added in v1.1.3

func GetEngineEndpoint(volume *Volume, ip string) (string, error)

func GetEngineProcessFrontend added in v0.8.0

func GetEngineProcessFrontend(volumeFrontend longhorn.VolumeFrontend) (string, error)

func ValidateReplicaURL

func ValidateReplicaURL(url string) error

Types

type BackingImageDataSourceClient added in v1.2.0

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

func NewBackingImageDataSourceClient added in v1.2.0

func NewBackingImageDataSourceClient(ip string) *BackingImageDataSourceClient

func (*BackingImageDataSourceClient) Get added in v1.2.0

type BackingImageDataSourceInfo added in v1.2.0

type BackingImageDataSourceInfo struct {
	DiskUUID   string            `json:"diskUUID"`
	SourceType string            `json:"sourceType"`
	Parameters map[string]string `json:"parameters"`

	FileName        string `json:"fileName"`
	State           string `json:"state"`
	Size            int64  `json:"size"`
	Progress        int    `json:"progress"`
	ProcessedSize   int64  `json:"processedSize"`
	CurrentChecksum string `json:"currentChecksum"`
	Message         string `json:"message"`
}

type BackingImageManagerClient added in v1.1.1

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

func NewBackingImageManagerClient added in v1.1.1

func NewBackingImageManagerClient(bim *longhorn.BackingImageManager) (*BackingImageManagerClient, error)

func (*BackingImageManagerClient) Delete added in v1.1.1

func (c *BackingImageManagerClient) Delete(name string) error

func (*BackingImageManagerClient) Fetch added in v1.2.0

func (c *BackingImageManagerClient) Fetch(name, uuid, fileName, checksum string, size int64) (*longhorn.BackingImageFileInfo, error)

func (*BackingImageManagerClient) Get added in v1.1.1

func (*BackingImageManagerClient) List added in v1.1.1

func (*BackingImageManagerClient) Sync added in v1.1.1

func (c *BackingImageManagerClient) Sync(name, uuid, checksum, fromHost, toHost string, size int64) (*longhorn.BackingImageFileInfo, error)

func (*BackingImageManagerClient) VersionGet added in v1.1.1

func (c *BackingImageManagerClient) VersionGet() (int, int, error)

func (*BackingImageManagerClient) Watch added in v1.1.1

type Backup

type Backup struct {
	Name                   string               `json:"name"`
	State                  longhorn.BackupState `json:"state"`
	URL                    string               `json:"url"`
	SnapshotName           string               `json:"snapshotName"`
	SnapshotCreated        string               `json:"snapshotCreated"`
	Created                string               `json:"created"`
	Size                   string               `json:"size"`
	Labels                 map[string]string    `json:"labels"`
	VolumeName             string               `json:"volumeName"`
	VolumeSize             string               `json:"volumeSize"`
	VolumeCreated          string               `json:"volumeCreated"`
	VolumeBackingImageName string               `json:"volumeBackingImageName"`
	Messages               map[string]string    `json:"messages"`
}

type BackupCreateInfo added in v0.6.0

type BackupCreateInfo struct {
	BackupID       string
	ReplicaAddress string
	IsIncremental  bool
}

type BackupMonitor added in v1.2.3

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

func NewBackupMonitor added in v1.2.3

func NewBackupMonitor(logger logrus.FieldLogger,
	backup *longhorn.Backup, volume *longhorn.Volume, backupTargetClient *BackupTargetClient,
	biChecksum string, engineClient EngineClient, syncCallback func(key string)) (*BackupMonitor, error)

func (*BackupMonitor) Close added in v1.2.3

func (m *BackupMonitor) Close()

func (*BackupMonitor) GetBackupStatus added in v1.2.3

func (m *BackupMonitor) GetBackupStatus() longhorn.BackupStatus

type BackupTarget

type BackupTarget struct {
	BackupTargetURL  string `json:"backupTargetURL"`
	CredentialSecret string `json:"credentialSecret"`
	PollInterval     string `json:"pollInterval"`
	Available        bool   `json:"available"`
	Message          string `json:"message"`
}

type BackupTargetClient added in v1.2.0

type BackupTargetClient struct {
	Image      string
	URL        string
	Credential map[string]string
}

func NewBackupTargetClient added in v1.2.0

func NewBackupTargetClient(defaultEngineImage, url string, credential map[string]string) *BackupTargetClient

NewBackupTargetClient returns the backup target client

func (*BackupTargetClient) DeleteBackup added in v1.2.0

func (btc *BackupTargetClient) DeleteBackup(backupURL string) error

DeleteBackup deletes the backup from the remote backup target

func (*BackupTargetClient) DeleteBackupVolume added in v1.2.0

func (btc *BackupTargetClient) DeleteBackupVolume(volumeName string) error

DeleteBackupVolume deletes the backup volume from the remote backup target

func (*BackupTargetClient) ExecuteEngineBinary added in v1.2.0

func (btc *BackupTargetClient) ExecuteEngineBinary(args ...string) (string, error)

func (*BackupTargetClient) ExecuteEngineBinaryWithoutTimeout added in v1.2.0

func (btc *BackupTargetClient) ExecuteEngineBinaryWithoutTimeout(args ...string) (string, error)

func (*BackupTargetClient) GetConfigMetadata added in v1.2.0

func (btc *BackupTargetClient) GetConfigMetadata(url string) (*ConfigMetadata, error)

GetConfigMetadata returns the config metadata with the given URL

func (*BackupTargetClient) InspectBackupConfig added in v1.2.0

func (btc *BackupTargetClient) InspectBackupConfig(backupConfigURL string) (*Backup, error)

InspectBackupConfig inspects a backup config with the given backup config URL

func (*BackupTargetClient) InspectBackupVolumeConfig added in v1.2.0

func (btc *BackupTargetClient) InspectBackupVolumeConfig(backupVolumeURL string) (*BackupVolume, error)

InspectBackupVolumeConfig inspects a backup volume config with the given volume config URL

func (*BackupTargetClient) ListBackupNames added in v1.2.0

func (btc *BackupTargetClient) ListBackupNames(volumeName string) ([]string, error)

ListBackupNames returns a list of backup names

func (*BackupTargetClient) ListBackupVolumeNames added in v1.2.0

func (btc *BackupTargetClient) ListBackupVolumeNames() ([]string, error)

ListBackupVolumeNames returns a list of backup volume names

func (*BackupTargetClient) LonghornEngineBinary added in v1.2.0

func (btc *BackupTargetClient) LonghornEngineBinary() string

type BackupVolume

type BackupVolume struct {
	Name                 string             `json:"name"`
	Size                 string             `json:"size"`
	Labels               map[string]string  `json:"labels"`
	Created              string             `json:"created"`
	LastBackupName       string             `json:"lastBackupName"`
	LastBackupAt         string             `json:"lastBackupAt"`
	DataStored           string             `json:"dataStored"`
	Messages             map[string]string  `json:"messages"`
	Backups              map[string]*Backup `json:"backups"`
	BackingImageName     string             `json:"backingImageName"`
	BackingImageChecksum string             `json:"backingImageChecksum"`
}

type ConfigMetadata added in v1.2.0

type ConfigMetadata struct {
	ModificationTime time.Time `json:"modificationTime"`
}

type Controller

type Controller struct {
	URL    string
	NodeID string
}

type Engine

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

func (*Engine) BackupRestore

func (e *Engine) BackupRestore(backupTarget, backupName, backupVolumeName, lastRestored string, credential map[string]string) error

func (*Engine) BackupRestoreStatus added in v0.6.0

func (e *Engine) BackupRestoreStatus() (map[string]*longhorn.RestoreStatus, error)

func (*Engine) ExecuteEngineBinary

func (e *Engine) ExecuteEngineBinary(args ...string) (string, error)

func (*Engine) ExecuteEngineBinaryWithTimeout

func (e *Engine) ExecuteEngineBinaryWithTimeout(timeout time.Duration, args ...string) (string, error)

func (*Engine) ExecuteEngineBinaryWithoutTimeout added in v0.6.0

func (e *Engine) ExecuteEngineBinaryWithoutTimeout(envs []string, args ...string) (string, error)

func (*Engine) Expand added in v0.8.0

func (e *Engine) Expand(size int64) error

func (*Engine) FrontendShutdown added in v0.8.0

func (e *Engine) FrontendShutdown() error

func (*Engine) FrontendStart added in v0.8.0

func (e *Engine) FrontendStart(volumeFrontend longhorn.VolumeFrontend) error

func (*Engine) Info added in v0.5.0

func (e *Engine) Info() (*Volume, error)

func (*Engine) LonghornEngineBinary

func (e *Engine) LonghornEngineBinary() string

func (*Engine) Name

func (e *Engine) Name() string

func (*Engine) ReplicaAdd

func (e *Engine) ReplicaAdd(url string, isRestoreVolume bool) error

func (*Engine) ReplicaList

func (e *Engine) ReplicaList() (map[string]*Replica, error)

func (*Engine) ReplicaRebuildStatus added in v0.8.0

func (e *Engine) ReplicaRebuildStatus() (map[string]*longhorn.RebuildStatus, error)

func (*Engine) ReplicaRebuildVerify added in v1.1.0

func (e *Engine) ReplicaRebuildVerify(url string) error

func (*Engine) ReplicaRemove

func (e *Engine) ReplicaRemove(url string) error

func (*Engine) SnapshotBackup

func (e *Engine) SnapshotBackup(backupName, snapName, backupTarget, backingImageName, backingImageChecksum string, labels, credential map[string]string) (string, string, error)

func (*Engine) SnapshotBackupStatus added in v0.6.0

func (e *Engine) SnapshotBackupStatus(backupName, replicaAddress string) (*longhorn.EngineBackupStatus, error)

func (*Engine) SnapshotClone added in v1.2.0

func (e *Engine) SnapshotClone(snapshotName, fromControllerAddress string) error

func (*Engine) SnapshotCloneStatus added in v1.2.0

func (e *Engine) SnapshotCloneStatus() (map[string]*longhorn.SnapshotCloneStatus, error)

func (*Engine) SnapshotCreate

func (e *Engine) SnapshotCreate(name string, labels map[string]string) (string, error)

func (*Engine) SnapshotDelete

func (e *Engine) SnapshotDelete(name string) error

func (*Engine) SnapshotGet

func (e *Engine) SnapshotGet(name string) (*longhorn.Snapshot, error)

func (*Engine) SnapshotList

func (e *Engine) SnapshotList() (map[string]*longhorn.Snapshot, error)

func (*Engine) SnapshotPurge

func (e *Engine) SnapshotPurge() error

func (*Engine) SnapshotPurgeStatus added in v0.6.0

func (e *Engine) SnapshotPurgeStatus() (map[string]*longhorn.PurgeStatus, error)

func (*Engine) SnapshotRevert

func (e *Engine) SnapshotRevert(name string) error

func (*Engine) Version

func (e *Engine) Version(clientOnly bool) (*EngineVersion, error)

type EngineClient

type EngineClient interface {
	Name() string
	Version(clientOnly bool) (*EngineVersion, error)

	Info() (*Volume, error)
	Expand(size int64) error

	FrontendStart(volumeFrontend longhorn.VolumeFrontend) error
	FrontendShutdown() error

	ReplicaList() (map[string]*Replica, error)
	ReplicaAdd(url string, isRestoreVolume bool) error
	ReplicaRemove(url string) error
	ReplicaRebuildStatus() (map[string]*longhorn.RebuildStatus, error)
	ReplicaRebuildVerify(url string) error

	SnapshotCreate(name string, labels map[string]string) (string, error)
	SnapshotList() (map[string]*longhorn.Snapshot, error)
	SnapshotGet(name string) (*longhorn.Snapshot, error)
	SnapshotDelete(name string) error
	SnapshotRevert(name string) error
	SnapshotPurge() error
	SnapshotPurgeStatus() (map[string]*longhorn.PurgeStatus, error)
	SnapshotBackup(backupName, snapName, backupTarget, backingImageName, backingImageChecksum string, labels, credential map[string]string) (string, string, error)
	SnapshotBackupStatus(backupName, replicaAddress string) (*longhorn.EngineBackupStatus, error)
	SnapshotCloneStatus() (map[string]*longhorn.SnapshotCloneStatus, error)
	SnapshotClone(snapshotName, fromControllerAddress string) error

	BackupRestore(backupTarget, backupName, backupVolume, lastRestored string, credential map[string]string) error
	BackupRestoreStatus() (map[string]*longhorn.RestoreStatus, error)
}

type EngineClientCollection

type EngineClientCollection interface {
	NewEngineClient(request *EngineClientRequest) (EngineClient, error)
}

type EngineClientRequest

type EngineClientRequest struct {
	VolumeName  string
	EngineImage string
	IP          string
	Port        int
}

type EngineCollection

type EngineCollection struct{}

func (*EngineCollection) NewEngineClient

func (c *EngineCollection) NewEngineClient(request *EngineClientRequest) (EngineClient, error)

type EngineSimulator

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

func (*EngineSimulator) BackupRestore added in v0.6.0

func (e *EngineSimulator) BackupRestore(backupTarget, backupName, backupVolume, lastRestored string, credential map[string]string) error

func (*EngineSimulator) BackupRestoreStatus added in v0.6.0

func (e *EngineSimulator) BackupRestoreStatus() (map[string]*longhorn.RestoreStatus, error)

func (*EngineSimulator) Expand added in v0.8.0

func (e *EngineSimulator) Expand(size int64) error

func (*EngineSimulator) FrontendShutdown added in v0.8.0

func (e *EngineSimulator) FrontendShutdown() error

func (*EngineSimulator) FrontendStart added in v0.8.0

func (e *EngineSimulator) FrontendStart(volumeFrontend longhorn.VolumeFrontend) error

func (*EngineSimulator) Info added in v0.5.0

func (e *EngineSimulator) Info() (*Volume, error)

func (*EngineSimulator) Name

func (e *EngineSimulator) Name() string

func (*EngineSimulator) ReplicaAdd

func (e *EngineSimulator) ReplicaAdd(url string, isRestoreVolume bool) error

func (*EngineSimulator) ReplicaList

func (e *EngineSimulator) ReplicaList() (map[string]*Replica, error)

func (*EngineSimulator) ReplicaRebuildStatus added in v0.8.0

func (e *EngineSimulator) ReplicaRebuildStatus() (map[string]*longhorn.RebuildStatus, error)

func (*EngineSimulator) ReplicaRebuildVerify added in v1.1.0

func (e *EngineSimulator) ReplicaRebuildVerify(url string) error

func (*EngineSimulator) ReplicaRemove

func (e *EngineSimulator) ReplicaRemove(addr string) error

func (*EngineSimulator) SimulateStopReplica

func (e *EngineSimulator) SimulateStopReplica(addr string) error

func (*EngineSimulator) SnapshotBackup

func (e *EngineSimulator) SnapshotBackup(backupName, snapName, backupTarget, backingImageName, backingImageChecksum string, labels, credential map[string]string) (string, string, error)

func (*EngineSimulator) SnapshotBackupStatus added in v0.6.0

func (e *EngineSimulator) SnapshotBackupStatus(backupName, replicaAddress string) (*longhorn.EngineBackupStatus, error)

func (*EngineSimulator) SnapshotClone added in v1.2.0

func (e *EngineSimulator) SnapshotClone(snapshotName, fromControllerAddress string) error

func (*EngineSimulator) SnapshotCloneStatus added in v1.2.0

func (e *EngineSimulator) SnapshotCloneStatus() (map[string]*longhorn.SnapshotCloneStatus, error)

func (*EngineSimulator) SnapshotCreate

func (e *EngineSimulator) SnapshotCreate(name string, labels map[string]string) (string, error)

func (*EngineSimulator) SnapshotDelete

func (e *EngineSimulator) SnapshotDelete(name string) error

func (*EngineSimulator) SnapshotGet

func (e *EngineSimulator) SnapshotGet(name string) (*longhorn.Snapshot, error)

func (*EngineSimulator) SnapshotList

func (e *EngineSimulator) SnapshotList() (map[string]*longhorn.Snapshot, error)

func (*EngineSimulator) SnapshotPurge

func (e *EngineSimulator) SnapshotPurge() error

func (*EngineSimulator) SnapshotPurgeStatus added in v0.6.0

func (e *EngineSimulator) SnapshotPurgeStatus() (map[string]*longhorn.PurgeStatus, error)

func (*EngineSimulator) SnapshotRevert

func (e *EngineSimulator) SnapshotRevert(name string) error

func (*EngineSimulator) Version

func (e *EngineSimulator) Version(clientOnly bool) (*EngineVersion, error)

type EngineSimulatorCollection

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

func NewEngineSimulatorCollection

func NewEngineSimulatorCollection() *EngineSimulatorCollection

func (*EngineSimulatorCollection) CreateEngineSimulator

func (c *EngineSimulatorCollection) CreateEngineSimulator(request *EngineSimulatorRequest) error

func (*EngineSimulatorCollection) DeleteEngineSimulator

func (c *EngineSimulatorCollection) DeleteEngineSimulator(volumeName string) error

func (*EngineSimulatorCollection) GetEngineSimulator

func (c *EngineSimulatorCollection) GetEngineSimulator(volumeName string) (*EngineSimulator, error)

func (*EngineSimulatorCollection) NewEngineClient

func (c *EngineSimulatorCollection) NewEngineClient(request *EngineClientRequest) (EngineClient, error)

type EngineSimulatorRequest

type EngineSimulatorRequest struct {
	VolumeName     string
	VolumeSize     int64
	ControllerAddr string
	ReplicaAddrs   []string
}

type EngineVersion

type EngineVersion struct {
	ClientVersion *longhorn.EngineVersionDetails `json:"clientVersion"`
	ServerVersion *longhorn.EngineVersionDetails `json:"serverVersion"`
}

type InstanceManagerClient added in v0.8.0

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

func NewInstanceManagerClient added in v0.8.0

func NewInstanceManagerClient(im *longhorn.InstanceManager) (*InstanceManagerClient, error)

func (*InstanceManagerClient) EngineProcessCreate added in v0.8.0

func (c *InstanceManagerClient) EngineProcessCreate(engineName, volumeName, engineImage string, volumeFrontend longhorn.VolumeFrontend, replicaAddressMap map[string]string, revCounterDisabled bool, salvageRequested bool) (*longhorn.InstanceProcess, error)

func (*InstanceManagerClient) EngineProcessUpgrade added in v0.8.0

func (c *InstanceManagerClient) EngineProcessUpgrade(engineName, volumeName, engineImage string, volumeFrontend longhorn.VolumeFrontend, replicaAddressMap map[string]string) (*longhorn.InstanceProcess, error)

func (*InstanceManagerClient) ProcessDelete added in v0.8.0

func (c *InstanceManagerClient) ProcessDelete(name string) error

func (*InstanceManagerClient) ProcessGet added in v0.8.0

func (c *InstanceManagerClient) ProcessGet(name string) (*longhorn.InstanceProcess, error)

func (*InstanceManagerClient) ProcessList added in v0.8.0

func (c *InstanceManagerClient) ProcessList() (map[string]longhorn.InstanceProcess, error)

func (*InstanceManagerClient) ProcessLog added in v0.8.0

func (c *InstanceManagerClient) ProcessLog(name string) (*imapi.LogStream, error)

func (*InstanceManagerClient) ProcessWatch added in v0.8.0

func (c *InstanceManagerClient) ProcessWatch() (*imapi.ProcessStream, error)

func (*InstanceManagerClient) ReplicaProcessCreate added in v0.8.0

func (c *InstanceManagerClient) ReplicaProcessCreate(replicaName, engineImage, dataPath, backingImagePath string, size int64, revCounterDisabled bool) (*longhorn.InstanceProcess, error)

func (*InstanceManagerClient) VersionGet added in v0.8.0

func (c *InstanceManagerClient) VersionGet() (int, int, error)

type LauncherVolumeInfo

type LauncherVolumeInfo struct {
	Volume   string `json:"volume,omitempty"`
	Frontend string `json:"frontend,omitempty"`
	Endpoint string `json:"endpoint,omitempty"`
}

type Replica

type Replica struct {
	URL  string
	Mode longhorn.ReplicaMode
}

type ReplicaError added in v1.0.1

type ReplicaError struct {
	Address string
	Message string
}

func (ReplicaError) Error added in v1.0.1

func (e ReplicaError) Error() string

type TaskError added in v1.0.1

type TaskError struct {
	ReplicaErrors []ReplicaError
}

func (TaskError) Error added in v1.0.1

func (e TaskError) Error() string

type Volume

type Volume struct {
	Name                  string `json:"name"`
	Size                  int64  `json:"size"`
	ReplicaCount          int    `json:"replicaCount"`
	Endpoint              string `json:"endpoint"`
	Frontend              string `json:"frontend"`
	FrontendState         string `json:"frontendState"`
	IsExpanding           bool   `json:"isExpanding"`
	LastExpansionError    string `json:"lastExpansionError"`
	LastExpansionFailedAt string `json:"lastExpansionFailedAt"`
}

Jump to

Keyboard shortcuts

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