kubecli

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: May 14, 2019 License: Apache-2.0 Imports: 65 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ApiGroupName = "/apis/" + v1.SubresourceGroupName
)
View Source
const (
	WebsocketMessageBufferSize = 10240
)

Variables

View Source
var GetKubevirtClientFromClientConfig = func(cmdConfig clientcmd.ClientConfig) (KubevirtClient, error) {
	config, err := cmdConfig.ClientConfig()
	if err != nil {
		return nil, err
	}
	return GetKubevirtClientFromRESTConfig(config)

}

this function is defined as a closure so iut could be overwritten by unit tests

Functions

func DefaultClientConfig

func DefaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig

DefaultClientConfig creates a clientcmd.ClientConfig with the following hierarchy:

  1. Use the kubeconfig builder. The number of merges and overrides here gets a little crazy. Stay with me.

  2. Merge the kubeconfig itself. This is done with the following hierarchy rules:

  3. CommandLineLocation - this parsed from the command line, so it must be late bound. If you specify this, then no other kubeconfig files are merged. This file must exist.

  4. If $KUBECONFIG is set, then it is treated as a list of files that should be merged.

  5. HomeDirectoryLocation Empty filenames are ignored. Files with non-deserializable content produced errors. The first file to set a particular value or map key wins and the value or map key is never changed. This means that the first file to set CurrentContext will have its context preserved. It also means that if two files specify a "red-user", only values from the first file's red-user are used. Even non-conflicting entries from the second file's "red-user" are discarded.

  6. Determine the context to use based on the first hit in this chain

  7. command line argument - again, parsed from the command line, so it must be late bound

  8. CurrentContext from the merged kubeconfig file

  9. Empty is allowed at this stage

  10. Determine the cluster info and auth info to use. At this point, we may or may not have a context. They are built based on the first hit in this chain. (run it twice, once for auth, once for cluster)

  11. command line argument

  12. If context is present, then use the context value

  13. Empty is allowed

  14. Determine the actual cluster info to use. At this point, we may or may not have a cluster info. Build each piece of the cluster info based on the chain:

  15. command line argument

  16. If cluster info is present and a value for the attribute is present, use it.

  17. If you don't have a server location, bail.

  18. Auth info is build using the same rules as cluster info, EXCEPT that you can only have one authentication technique per auth info. The following conditions result in an error:

  19. If there are two conflicting techniques specified from the command line, fail.

  20. If the command line does not specify one, and the auth info has conflicting techniques, fail.

  21. If the command line specifies one and the auth info specifies another, honor the command line technique.

  22. Use default values and potentially prompt for auth information

    However, if it appears that we're running in a kubernetes cluster container environment, then run with the auth info kubernetes mounted for us. Specifically: The env vars KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT are set, and the file /var/run/secrets/kubernetes.io/serviceaccount/token exists and is not a directory.

Initially copied from https://github.com/kubernetes/kubernetes/blob/09f321c80bfc9bca63a5530b56d7a1a3ba80ba9b/pkg/kubectl/cmd/util/factory_client_access.go#L174

func GetConfig

func GetConfig() (*restclient.Config, error)

func GetKubevirtClientConfig

func GetKubevirtClientConfig() (*rest.Config, error)

func NewKubeVirtList

func NewKubeVirtList(kubevirts ...v1.KubeVirt) *v1.KubeVirtList

func NewMinimalKubeVirt

func NewMinimalKubeVirt(name string) *v1.KubeVirt

func NewMinimalMigration

func NewMinimalMigration(name string) *v1.VirtualMachineInstanceMigration

func NewMinimalVM

func NewMinimalVM(name string) *v1.VirtualMachine

func NewMinimalVirtualMachineInstanceReplicaSet

func NewMinimalVirtualMachineInstanceReplicaSet(name string) *v1.VirtualMachineInstanceReplicaSet

func NewVMList

func NewVMList(vms ...v1.VirtualMachine) *v1.VirtualMachineList

func RequestFromConfig

func RequestFromConfig(config *rest.Config, vmi string, namespace string, resource string) (*http.Request, error)

Types

type AsyncSubresourceError

type AsyncSubresourceError struct {
	StatusCode int
	// contains filtered or unexported fields
}

func (*AsyncSubresourceError) Error

func (a *AsyncSubresourceError) Error() string

func (*AsyncSubresourceError) GetStatusCode

func (a *AsyncSubresourceError) GetStatusCode() int

type BinaryReadWriter

type BinaryReadWriter struct {
	Conn *websocket.Conn
}

func (*BinaryReadWriter) Read

func (s *BinaryReadWriter) Read(p []byte) (int, error)

func (*BinaryReadWriter) Write

func (s *BinaryReadWriter) Write(p []byte) (int, error)

type KubeVirtInterface

type KubeVirtInterface interface {
	Get(name string, options *k8smetav1.GetOptions) (*v1.KubeVirt, error)
	List(opts *k8smetav1.ListOptions) (*v1.KubeVirtList, error)
	Create(instance *v1.KubeVirt) (*v1.KubeVirt, error)
	Update(*v1.KubeVirt) (*v1.KubeVirt, error)
	Delete(name string, options *k8smetav1.DeleteOptions) error
	Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.KubeVirt, err error)
}

type KubevirtClient

type KubevirtClient interface {
	VirtualMachineInstance(namespace string) VirtualMachineInstanceInterface
	VirtualMachineInstanceMigration(namespace string) VirtualMachineInstanceMigrationInterface
	ReplicaSet(namespace string) ReplicaSetInterface
	VirtualMachine(namespace string) VirtualMachineInterface
	KubeVirt(namespace string) KubeVirtInterface
	ServerVersion() *ServerVersion
	RestClient() *rest.RESTClient
	CdiClient() cdiclient.Interface
	NetworkClient() networkclient.Interface
	ExtensionsClient() extclient.Interface
	SecClient() secv1.SecurityV1Interface
	DiscoveryClient() discovery.DiscoveryInterface
	kubernetes.Interface
	Config() *rest.Config
}

func GetInvalidKubevirtClientFromClientConfig

func GetInvalidKubevirtClientFromClientConfig(cmdConfig clientcmd.ClientConfig) (KubevirtClient, error)

GetInvalidKubevirtClientFromClientConfig is an entry point for testing case where client should be invalid

func GetKubevirtClient

func GetKubevirtClient() (KubevirtClient, error)

func GetKubevirtClientFromFlags

func GetKubevirtClientFromFlags(master string, kubeconfig string) (KubevirtClient, error)

func GetKubevirtClientFromRESTConfig

func GetKubevirtClientFromRESTConfig(config *rest.Config) (KubevirtClient, error)

func GetKubevirtSubresourceClient

func GetKubevirtSubresourceClient() (KubevirtClient, error)

func GetKubevirtSubresourceClientFromFlags

func GetKubevirtSubresourceClientFromFlags(master string, kubeconfig string) (KubevirtClient, error)

func GetMockKubevirtClientFromClientConfig

func GetMockKubevirtClientFromClientConfig(cmdConfig clientcmd.ClientConfig) (KubevirtClient, error)

GetMockKubevirtClientFromClientConfig is an entry point for testing, could be used to override GetKubevirtClientFromClientConfig

type MockKubeVirtInterface

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

Mock of KubeVirtInterface interface

func NewMockKubeVirtInterface

func NewMockKubeVirtInterface(ctrl *gomock.Controller) *MockKubeVirtInterface

func (*MockKubeVirtInterface) Create

func (_m *MockKubeVirtInterface) Create(instance *v111.KubeVirt) (*v111.KubeVirt, error)

func (*MockKubeVirtInterface) Delete

func (_m *MockKubeVirtInterface) Delete(name string, options *v11.DeleteOptions) error

func (*MockKubeVirtInterface) EXPECT

func (_m *MockKubeVirtInterface) EXPECT() *_MockKubeVirtInterfaceRecorder

func (*MockKubeVirtInterface) Get

func (_m *MockKubeVirtInterface) Get(name string, options *v11.GetOptions) (*v111.KubeVirt, error)

func (*MockKubeVirtInterface) List

func (*MockKubeVirtInterface) Patch

func (_m *MockKubeVirtInterface) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (*v111.KubeVirt, error)

func (*MockKubeVirtInterface) Update

func (_m *MockKubeVirtInterface) Update(_param0 *v111.KubeVirt) (*v111.KubeVirt, error)

type MockKubevirtClient

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

Mock of KubevirtClient interface

var MockKubevirtClientInstance *MockKubevirtClient

MockKubevirtClientInstance is a reference to the kubevirt client that could be manipulated by the test code

func NewMockKubevirtClient

func NewMockKubevirtClient(ctrl *gomock.Controller) *MockKubevirtClient

func (*MockKubevirtClient) Admissionregistration

func (*MockKubevirtClient) AdmissionregistrationV1alpha1

func (_m *MockKubevirtClient) AdmissionregistrationV1alpha1() v1alpha1.AdmissionregistrationV1alpha1Interface

func (*MockKubevirtClient) AdmissionregistrationV1beta1

func (_m *MockKubevirtClient) AdmissionregistrationV1beta1() v1beta1.AdmissionregistrationV1beta1Interface

func (*MockKubevirtClient) Apps

func (*MockKubevirtClient) AppsV1

func (_m *MockKubevirtClient) AppsV1() v12.AppsV1Interface

func (*MockKubevirtClient) AppsV1beta1

func (*MockKubevirtClient) AppsV1beta2

func (*MockKubevirtClient) Authentication

func (_m *MockKubevirtClient) Authentication() v13.AuthenticationV1Interface

func (*MockKubevirtClient) AuthenticationV1

func (_m *MockKubevirtClient) AuthenticationV1() v13.AuthenticationV1Interface

func (*MockKubevirtClient) AuthenticationV1beta1

func (_m *MockKubevirtClient) AuthenticationV1beta1() v1beta11.AuthenticationV1beta1Interface

func (*MockKubevirtClient) Authorization

func (_m *MockKubevirtClient) Authorization() v14.AuthorizationV1Interface

func (*MockKubevirtClient) AuthorizationV1

func (_m *MockKubevirtClient) AuthorizationV1() v14.AuthorizationV1Interface

func (*MockKubevirtClient) AuthorizationV1beta1

func (_m *MockKubevirtClient) AuthorizationV1beta1() v1beta12.AuthorizationV1beta1Interface

func (*MockKubevirtClient) Autoscaling

func (_m *MockKubevirtClient) Autoscaling() v15.AutoscalingV1Interface

func (*MockKubevirtClient) AutoscalingV1

func (_m *MockKubevirtClient) AutoscalingV1() v15.AutoscalingV1Interface

func (*MockKubevirtClient) AutoscalingV2beta1

func (_m *MockKubevirtClient) AutoscalingV2beta1() v2beta1.AutoscalingV2beta1Interface

func (*MockKubevirtClient) AutoscalingV2beta2

func (_m *MockKubevirtClient) AutoscalingV2beta2() v2beta2.AutoscalingV2beta2Interface

func (*MockKubevirtClient) Batch

func (*MockKubevirtClient) BatchV1

func (_m *MockKubevirtClient) BatchV1() v16.BatchV1Interface

func (*MockKubevirtClient) BatchV1beta1

func (*MockKubevirtClient) BatchV2alpha1

func (*MockKubevirtClient) CdiClient

func (_m *MockKubevirtClient) CdiClient() versioned0.Interface

func (*MockKubevirtClient) Certificates

func (*MockKubevirtClient) CertificatesV1beta1

func (_m *MockKubevirtClient) CertificatesV1beta1() v1beta14.CertificatesV1beta1Interface

func (*MockKubevirtClient) Config

func (_m *MockKubevirtClient) Config() *rest.Config

func (*MockKubevirtClient) Coordination

func (*MockKubevirtClient) CoordinationV1beta1

func (_m *MockKubevirtClient) CoordinationV1beta1() v1beta15.CoordinationV1beta1Interface

func (*MockKubevirtClient) Core

func (*MockKubevirtClient) CoreV1

func (_m *MockKubevirtClient) CoreV1() v17.CoreV1Interface

func (*MockKubevirtClient) Discovery

func (*MockKubevirtClient) DiscoveryClient

func (_m *MockKubevirtClient) DiscoveryClient() discovery.DiscoveryInterface

func (*MockKubevirtClient) EXPECT

func (_m *MockKubevirtClient) EXPECT() *_MockKubevirtClientRecorder

func (*MockKubevirtClient) Events

func (*MockKubevirtClient) EventsV1beta1

func (*MockKubevirtClient) Extensions

func (*MockKubevirtClient) ExtensionsClient

func (_m *MockKubevirtClient) ExtensionsClient() clientset.Interface

func (*MockKubevirtClient) ExtensionsV1beta1

func (_m *MockKubevirtClient) ExtensionsV1beta1() v1beta17.ExtensionsV1beta1Interface

func (*MockKubevirtClient) KubeVirt

func (_m *MockKubevirtClient) KubeVirt(namespace string) KubeVirtInterface

func (*MockKubevirtClient) NetworkClient

func (_m *MockKubevirtClient) NetworkClient() versioned.Interface

func (*MockKubevirtClient) Networking

func (_m *MockKubevirtClient) Networking() v18.NetworkingV1Interface

func (*MockKubevirtClient) NetworkingV1

func (_m *MockKubevirtClient) NetworkingV1() v18.NetworkingV1Interface

func (*MockKubevirtClient) Policy

func (*MockKubevirtClient) PolicyV1beta1

func (*MockKubevirtClient) Rbac

func (*MockKubevirtClient) RbacV1

func (_m *MockKubevirtClient) RbacV1() v19.RbacV1Interface

func (*MockKubevirtClient) RbacV1alpha1

func (*MockKubevirtClient) RbacV1beta1

func (*MockKubevirtClient) ReplicaSet

func (_m *MockKubevirtClient) ReplicaSet(namespace string) ReplicaSetInterface

func (*MockKubevirtClient) RestClient

func (_m *MockKubevirtClient) RestClient() *rest.RESTClient

func (*MockKubevirtClient) Scheduling

func (*MockKubevirtClient) SchedulingV1alpha1

func (_m *MockKubevirtClient) SchedulingV1alpha1() v1alpha11.SchedulingV1alpha1Interface

func (*MockKubevirtClient) SchedulingV1beta1

func (*MockKubevirtClient) SecClient

func (_m *MockKubevirtClient) SecClient() v1.SecurityV1Interface

func (*MockKubevirtClient) ServerVersion

func (_m *MockKubevirtClient) ServerVersion() *ServerVersion

func (*MockKubevirtClient) Settings

func (*MockKubevirtClient) SettingsV1alpha1

func (*MockKubevirtClient) Storage

func (*MockKubevirtClient) StorageV1

func (_m *MockKubevirtClient) StorageV1() v110.StorageV1Interface

func (*MockKubevirtClient) StorageV1alpha1

func (*MockKubevirtClient) StorageV1beta1

func (*MockKubevirtClient) VirtualMachine

func (_m *MockKubevirtClient) VirtualMachine(namespace string) VirtualMachineInterface

func (*MockKubevirtClient) VirtualMachineInstance

func (_m *MockKubevirtClient) VirtualMachineInstance(namespace string) VirtualMachineInstanceInterface

func (*MockKubevirtClient) VirtualMachineInstanceMigration

func (_m *MockKubevirtClient) VirtualMachineInstanceMigration(namespace string) VirtualMachineInstanceMigrationInterface

type MockReplicaSetInterface

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

Mock of ReplicaSetInterface interface

func NewMockReplicaSetInterface

func NewMockReplicaSetInterface(ctrl *gomock.Controller) *MockReplicaSetInterface

func (*MockReplicaSetInterface) Create

func (*MockReplicaSetInterface) Delete

func (_m *MockReplicaSetInterface) Delete(name string, options *v11.DeleteOptions) error

func (*MockReplicaSetInterface) EXPECT

func (_m *MockReplicaSetInterface) EXPECT() *_MockReplicaSetInterfaceRecorder

func (*MockReplicaSetInterface) Get

func (*MockReplicaSetInterface) GetScale

func (_m *MockReplicaSetInterface) GetScale(replicaSetName string, options v11.GetOptions) (*v10.Scale, error)

func (*MockReplicaSetInterface) List

func (*MockReplicaSetInterface) Patch

func (_m *MockReplicaSetInterface) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (*v111.VirtualMachineInstanceReplicaSet, error)

func (*MockReplicaSetInterface) Update

func (*MockReplicaSetInterface) UpdateScale

func (_m *MockReplicaSetInterface) UpdateScale(replicaSetName string, scale *v10.Scale) (*v10.Scale, error)

type MockStreamInterface

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

Mock of StreamInterface interface

func NewMockStreamInterface

func NewMockStreamInterface(ctrl *gomock.Controller) *MockStreamInterface

func (*MockStreamInterface) EXPECT

func (_m *MockStreamInterface) EXPECT() *_MockStreamInterfaceRecorder

func (*MockStreamInterface) Stream

func (_m *MockStreamInterface) Stream(options StreamOptions) error

type MockVMIPresetInterface

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

Mock of VMIPresetInterface interface

func NewMockVMIPresetInterface

func NewMockVMIPresetInterface(ctrl *gomock.Controller) *MockVMIPresetInterface

func (*MockVMIPresetInterface) Create

func (*MockVMIPresetInterface) Delete

func (_m *MockVMIPresetInterface) Delete(name string, options *v11.DeleteOptions) error

func (*MockVMIPresetInterface) EXPECT

func (_m *MockVMIPresetInterface) EXPECT() *_MockVMIPresetInterfaceRecorder

func (*MockVMIPresetInterface) Get

func (*MockVMIPresetInterface) List

func (*MockVMIPresetInterface) Patch

func (_m *MockVMIPresetInterface) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (*v111.VirtualMachineInstancePreset, error)

func (*MockVMIPresetInterface) Update

type MockVirtualMachineInstanceInterface

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

Mock of VirtualMachineInstanceInterface interface

func NewMockVirtualMachineInstanceInterface

func NewMockVirtualMachineInstanceInterface(ctrl *gomock.Controller) *MockVirtualMachineInstanceInterface

func (*MockVirtualMachineInstanceInterface) Create

func (*MockVirtualMachineInstanceInterface) Delete

func (*MockVirtualMachineInstanceInterface) EXPECT

func (_m *MockVirtualMachineInstanceInterface) EXPECT() *_MockVirtualMachineInstanceInterfaceRecorder

func (*MockVirtualMachineInstanceInterface) Get

func (*MockVirtualMachineInstanceInterface) List

func (*MockVirtualMachineInstanceInterface) Patch

func (_m *MockVirtualMachineInstanceInterface) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (*v111.VirtualMachineInstance, error)

func (*MockVirtualMachineInstanceInterface) SerialConsole

func (_m *MockVirtualMachineInstanceInterface) SerialConsole(name string, timeout time.Duration) (StreamInterface, error)

func (*MockVirtualMachineInstanceInterface) Update

func (*MockVirtualMachineInstanceInterface) VNC

type MockVirtualMachineInstanceMigrationInterface

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

Mock of VirtualMachineInstanceMigrationInterface interface

func (*MockVirtualMachineInstanceMigrationInterface) Create

func (*MockVirtualMachineInstanceMigrationInterface) Delete

func (*MockVirtualMachineInstanceMigrationInterface) EXPECT

func (_m *MockVirtualMachineInstanceMigrationInterface) EXPECT() *_MockVirtualMachineInstanceMigrationInterfaceRecorder

func (*MockVirtualMachineInstanceMigrationInterface) Get

func (*MockVirtualMachineInstanceMigrationInterface) List

func (*MockVirtualMachineInstanceMigrationInterface) Patch

func (*MockVirtualMachineInstanceMigrationInterface) Update

type MockVirtualMachineInterface

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

Mock of VirtualMachineInterface interface

func NewMockVirtualMachineInterface

func NewMockVirtualMachineInterface(ctrl *gomock.Controller) *MockVirtualMachineInterface

func (*MockVirtualMachineInterface) Create

func (*MockVirtualMachineInterface) Delete

func (_m *MockVirtualMachineInterface) Delete(name string, options *v11.DeleteOptions) error

func (*MockVirtualMachineInterface) EXPECT

func (_m *MockVirtualMachineInterface) EXPECT() *_MockVirtualMachineInterfaceRecorder

func (*MockVirtualMachineInterface) Get

func (*MockVirtualMachineInterface) List

func (*MockVirtualMachineInterface) Patch

func (_m *MockVirtualMachineInterface) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (*v111.VirtualMachine, error)

func (*MockVirtualMachineInterface) Restart

func (_m *MockVirtualMachineInterface) Restart(name string) error

func (*MockVirtualMachineInterface) Start

func (_m *MockVirtualMachineInterface) Start(name string) error

func (*MockVirtualMachineInterface) Stop

func (_m *MockVirtualMachineInterface) Stop(name string) error

func (*MockVirtualMachineInterface) Update

type RoundTripCallback

type RoundTripCallback func(conn *websocket.Conn, resp *http.Response, err error) error

type ServerVersion

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

func (*ServerVersion) Get

func (v *ServerVersion) Get() (*version.Info, error)

type StreamInterface

type StreamInterface interface {
	Stream(options StreamOptions) error
}

type StreamOptions

type StreamOptions struct {
	In  io.Reader
	Out io.Writer
}

type VirtHandlerClient

type VirtHandlerClient interface {
	ForNode(nodeName string) VirtHandlerConn
}

func NewVirtHandlerClient

func NewVirtHandlerClient(client KubevirtClient) VirtHandlerClient

type VirtHandlerConn

type VirtHandlerConn interface {
	ConnectionDetails() (ip string, port string, err error)
	ConsoleURI(vmi *virtv1.VirtualMachineInstance) (*url.URL, error)
	Pod() (pod *v1.Pod, err error)
}

type VirtualMachineInstanceInterface

type VirtualMachineInstanceInterface interface {
	Get(name string, options *k8smetav1.GetOptions) (*v1.VirtualMachineInstance, error)
	List(opts *k8smetav1.ListOptions) (*v1.VirtualMachineInstanceList, error)
	Create(instance *v1.VirtualMachineInstance) (*v1.VirtualMachineInstance, error)
	Update(*v1.VirtualMachineInstance) (*v1.VirtualMachineInstance, error)
	Delete(name string, options *k8smetav1.DeleteOptions) error
	Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.VirtualMachineInstance, err error)
	SerialConsole(name string, timeout time.Duration) (StreamInterface, error)
	VNC(name string) (StreamInterface, error)
}

type VirtualMachineInterface

type VirtualMachineInterface interface {
	Get(name string, options *k8smetav1.GetOptions) (*v1.VirtualMachine, error)
	List(opts *k8smetav1.ListOptions) (*v1.VirtualMachineList, error)
	Create(*v1.VirtualMachine) (*v1.VirtualMachine, error)
	Update(*v1.VirtualMachine) (*v1.VirtualMachine, error)
	Delete(name string, options *k8smetav1.DeleteOptions) error
	Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.VirtualMachine, err error)
	Restart(name string) error
	Start(name string) error
	Stop(name string) error
}

VirtualMachineInterface provides convenience methods to work with virtual machines inside the cluster

type WebsocketRoundTripper

type WebsocketRoundTripper struct {
	Dialer *websocket.Dialer
	Do     RoundTripCallback
}

func (*WebsocketRoundTripper) RoundTrip

func (d *WebsocketRoundTripper) RoundTrip(r *http.Request) (*http.Response, error)

Jump to

Keyboard shortcuts

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