Documentation ¶
Overview ¶
Package ops provides a Golang-idiomatic API to the query and switching operations on Linux-kernel namespaces, hiding ioctl()s and syscalls.
Namespace Queries ¶
A particular Linux-kernel namespace can be referenced by a filesystem path, an open file descriptor, or an *os.File. Thus, this package defines the following three (six) namespace reference types:
- NamespacePath (and TypedNamespacePath)
- NamespaceFd (and TypedNamespaceFd)
- NamespaceFile (and TypedNamespaceFile)
The only difference between the NamespaceXXX and TypedNamespaceXXX reference types are: if the the type of namespace referenced is known beforehand, then this knowledge might be used to either optimize Type() lookups, or support Linux kernels before 4.11 which lack the ability to query the type of namespace via an ioctl(). In particular, this allows using the Visit() function (see below) to be used on such older kernels.
All these types of namespace references define the following query operations from the Relation interface (which map to a set of ioctl() calls, see: http://man7.org/linux/man-pages/man2/ioctl_ns.2.html, with the exception of the ID query):
- ID() returns the ID of the referenced namespace.
- User() returns the user namespace owning the referenced namespace.
- Parent() returns the parent namespace of the referenced namespace.
- OwnerUID() returns the UID of the owner of the referenced namespace.
- Type() returns the type of referenced namespace; CLONE_NEWNS, ...
NamespacePath and NamespaceFd can be easily converted from or to string and uintptr respectively.
netns := NamespacePath("/proc/self/ns/net") path := string(netns)
In case you want to use the Visit() function for switching namespaces and you need to support Linux kernels before 4.11 (which lack a required ioctl) then you can resort to TypedNamespacePath instead of NamespacePath.
netns := TypedNamespacePath("/proc/self/ns/net", species.CLONE_NEWNET)
As NamespaceFile mirrors os.File it cannot be directly converted in the way NamespacePath and NamespaceFd can. However, things are not overly complex either when keeping the following conversion examples in mind. To create a *NamespaceFile from an *os.File, such as returned by os.Open(), simply use the NewNamespaceFile() wrapper:
nsf, err := NewNamespaceFile(os.Open("/proc/self/ns/net"))
The rationale here is to model NamespaceFile as close as possible to os.File, and this implies that it should not be possible to create a NamespaceFile from a nil *os.File.
Please note that NewNamespaceFile() expects two parameters, an *os.File as well as an error. Simply specify a nil error in code contexts where there is clear that the *os.File is valid and there was no error in getting it.
Getting back an *os.File in case it is explicitly required is also simple:
f := &nsf.File
There's no need to panic because NamespaceFile embeds os.File, as opposed to *os.File, on purpose: os.File is a struct which consists solely of a single *os.file pointer to an implementation-internal structure. By embedding the outer struct instead of a pointer to it we mimic the original handling as close as possible, avoiding situations where a non-nil NamespaceFile points to a nil *os.File.
Switching Namespaces ¶
Switching namespaces is a slightly messy business in Golang: it is subject to both Golang runtime limitations as well as Linux kernel restrictions imposed especially on multi-threaded processes. In particular, after the Golang runtime has started, threads cannot change their user namespaces and mount namespaces anymore. Also, processes in general cannot switch themselves into a different PID namespace, but only their future child processes. Luckily, switching other types of namespaces is less restricted, such as switching a specific Go routine (rather, its locked OS thread) into another network namespace (and back again) is almost painless. However, OS threads need to hold both sufficient effective privileges for themselves as well as they must have sufficient (evaluated) capabilities in the namespace to switch to, please see http://man7.org/linux/man-pages/man2/setns.2.html and http://man7.org/linux/man-pages/man7/user_namespaces.7.html for details about the specific capabilities needed and how capabilities of a process with relation to a destination namespace are evaluated.
This package provides three means to execute some Go code in an OS thread with namespaces switched as specified:
- Go(f, namespaces...) -- asynchronous f in the specified namespaces.
- Execute(f, namespaces...) -- synchronous f in the specified namespaces with result.
- Visit(f, namespaces...) -- synchronous f in the specified namespaces in same Go routine.
These namespace-switching methods differ as follows: Go(f, namespaces...) acts very similar to the "go" statement in that it runs the given function f as a new go routine, but with its executing OS thread locked and switched into the specified namespaces.
Execute(f, namespaces...) is a synchronous version of Go() which waits for the namespace-switched f() to complete and to return some result (in form of an interface{}). Execute then returns this result to the caller.
Visit(f, namespaces...) is for those situations where the caller wants to avoid creating a new go routine, but is prepared to throw away its current go routine in case Visit() fails switching out of the namespaces afterwards, so the current OS thread and its go routine is toast.
Go ¶
The Go() function runs a function as a Go routine in the specified namespace(s). It returns an error in case switching into the specified namespaces fails, otherwise it simply returns nil. Please note that Go() doesn't call the specified function synchronously, but instead as a new Go routine.
netns := ops.NamespacePath("/proc/self/ns/net") err := ops.Go(func() { fmt.Println("Nobody expects the Spanish Inquisition!") }, netns)
While this might seem inconvenient at first, this design actually is very robust in view of any problems that might pop up when trying to switch the current (locaked) OS thread back into its original namespaces; the OS thread would be unrecoverable, but without a way to disassociate its Go routine from it. The Go() function avoids this situation by executing the desired function in a throw-away Go routine, so the Golang runtime can easily throw away the tainted OS thread which is locked to it afterwards. Sometimes, throwing things away is much cleaner (and not only for certain types of PPE).
If a Golang process needs to switch mount, PID, and user namespaces, we recommend using the gons package https://github.com/thediveo/gons in combination with its reexec subpackage (gons provide namespace switching before the Golang runtime starts, while reexec forks a Golang process and reexecutes it, with the reexecuted child then runnining a specific function only in the specified namespaces).
Execute ¶
Execute() is the synchronous twin of Go(): it waits for the namespace-switched function f() to complete and to return an interface{}. Execute() then passes on this result to its caller.
netns := ops.NamespacePath("/proc/self/ns/net") result, err := ops.Execute(func() interface{} { return "Nobody expects the Spanish Inquisition!" }, netns)
Visit ¶
If unsure, use Go() and Execute() instead. Only use Visit() if you understand that it can get you in really hot water and you are prepared to accept any consequences.
In case a go routine wants to hop into a namespace and then out of it again, without the help of a new go-routine, then Visit() helps with that. However, due to Golang's runtime design, if getting back to the original namespaces before the call to Visit() fails, then any such go routine must be prepare to sacrifice itself, because by then it has a locked OS thread on its back in an unknown namespace attachment state, and further namespace hopping might end badly.
If the caller is in a throw-away go routine itself and needs to run some code synchronously in other namespaces, then Visit() gives some optimization over Go() and especially Execute(), as it avoids spinning up another go routine.
Namespace IDs ¶
This package works with namespace identifiers in the form of tuples made from the inode number of a namespace and the associated filesystem device number (device ID). While at this time the inode number would be sufficient, as currently all namespaces are solely managed through the so-called "nsfs" filesystem, the tuple-based model follows the advice from http://man7.org/linux/man-pages/man7/namespaces.7.html as well as the dire kernel developer warning to create more havoc by deploying multiple namespace filesystem instances.
Comparing namespaces for equality is as simple as, as long both identifiers come from an origin honoring the device IDs:
if ns1.ID() == ns2.ID() {}
No special Equal() methods, nothing, nada, zilch. Just plain "==".
Unfortunately, the same kernel devs ignored their own warnings and happily output any namespace textual reference using only the inode number, such as in `net:[4026531905]`. And they left it to us to face the music they're playing; CLI tools so far only use the kernel's incomplete textual format. To ease a future transition, species.IDwithType("net:[...]") returns complete namespace identifier information by supplying the missing device ID for the current nsfs filesystem itself.
In consequence, user code should avoid creating any NamespaceIDs directly, but instead through IDwithType, such as:
nsid1, _ := ops.IDwithType("net:[4026531905]")
or, given the inode as a number, not text:
nsid1 := ops.NamespaceIDFromInode(4026531905)
Sigh.
Example (ID) ¶
id, _ := NamespacePath("/proc/self/ns/net").ID() fmt.Println("id of my network namespace:", id)
Output:
Example (OwnerUID) ¶
uid, _ := NamespacePath("/proc/self/ns/user").OwnerUID() fmt.Println("user namespace id owning my network namespace:", uid)
Output:
Example (Parent) ¶
parentuserns, _ := NamespacePath("/proc/self/ns/user").Parent() id, _ := parentuserns.ID() // Release OS-level resources held by the returned parent user namespace // reference. _ = parentuserns.(io.Closer).Close() fmt.Println("parent user namespace id of my user namespace:", id)
Output:
Example (Type) ¶
nstype, _ := NamespacePath("/proc/self/ns/pid").Type() fmt.Printf("0x%08x\n", uint(nstype)) fmt.Println(nstype.String())
Output: 0x20000000 CLONE_NEWPID
Example (User) ¶
userns, _ := NamespacePath("/proc/self/ns/net").User() id, _ := userns.ID() // Release OS-level resources held by the returned user namespace reference. _ = userns.(io.Closer).Close() fmt.Println("user namespace id owning my network namespace:", id)
Output:
Index ¶
- func Execute(f func() interface{}, nsrefs ...relations.Relation) (interface{}, error)
- func Go(f func(), nsrefs ...relations.Relation) error
- func Visit(f func(), nsrefs ...relations.Relation) (err error)
- type InvalidNamespaceError
- type NamespaceFd
- func (nsfd NamespaceFd) ID() (species.NamespaceID, error)
- func (nsfd NamespaceFd) NsFd() (fd int, closer opener.FdCloser, err error)
- func (nsfd NamespaceFd) OpenTypedReference() (relations.Relation, opener.ReferenceCloser, error)
- func (nsfd NamespaceFd) OwnerUID() (int, error)
- func (nsfd NamespaceFd) Parent() (relations.Relation, error)
- func (nsfd NamespaceFd) String() string
- func (nsfd NamespaceFd) Type() (species.NamespaceType, error)
- func (nsfd NamespaceFd) User() (relations.Relation, error)
- type NamespaceFile
- func (nsf NamespaceFile) ID() (species.NamespaceID, error)
- func (nsf NamespaceFile) NsFd() (int, opener.FdCloser, error)
- func (nsf NamespaceFile) OpenTypedReference() (relations.Relation, opener.ReferenceCloser, error)
- func (nsf NamespaceFile) OwnerUID() (int, error)
- func (nsf NamespaceFile) Parent() (relations.Relation, error)
- func (nsf NamespaceFile) String() (s string)
- func (nsf NamespaceFile) Type() (species.NamespaceType, error)
- func (nsf NamespaceFile) User() (relations.Relation, error)
- type NamespaceOperationError
- type NamespacePath
- func (nsp NamespacePath) ID() (species.NamespaceID, error)
- func (nsp NamespacePath) NsFd() (int, opener.FdCloser, error)
- func (nsp NamespacePath) OpenTypedReference() (relations.Relation, opener.ReferenceCloser, error)
- func (nsp NamespacePath) OwnerUID() (int, error)
- func (nsp NamespacePath) Parent() (relations.Relation, error)
- func (nsp NamespacePath) String() string
- func (nsp NamespacePath) Type() (species.NamespaceType, error)
- func (nsp NamespacePath) User() (relations.Relation, error)
- type TypedNamespaceFd
- type TypedNamespaceFile
- func (nsf TypedNamespaceFile) NsFd() (int, opener.FdCloser, error)
- func (nsf TypedNamespaceFile) OpenTypedReference() (relations.Relation, opener.ReferenceCloser, error)
- func (nsf TypedNamespaceFile) Parent() (relations.Relation, error)
- func (nsf TypedNamespaceFile) Type() (species.NamespaceType, error)
- type TypedNamespacePath
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Execute ¶
Execute a function synchronously while switched into the specified namespaces, then returns the interface{} outcome of calling the specified function. If switching fails, Execute returns an error instead.
func Go ¶
Go runs the specified function as a new Go routine and from a locked OS thread, while joined to the specified namespaces. When the specified function returns, its Go routine will also terminate and the underlying OS thread will be destroyed. This avoids subtle problems further down the road in case there were namespace switching issues which overwise would carry over into any code executed after invoking Go(). Go() returns nil if switching namespaces succeeded, else an error. Please note that Go() returns as soon as switching namespaces has finished. The specified function is then run in its own Go routine.
func Visit ¶
Visit locks the OS thread executing the current go routine, then switches the thread into the specified namespaces, and executes f(). Afterwards, it switches the namespaces back to their original settings and unlocks the underlying OS thread.
If switching namespaces back fails, then the OS thread is tainted and will remain locked. As simple as this sounds, Visit() is a dangerous thing: as long as the wheels keep spinning we're in the sunlit uplands. But as soon as the gears jam ... good luck. Visit() mainly exists for those optimizations where creating new OS threads is deemed to much overhead and namespace switch-back usually is possible. However, such uses must be prepared for Visit() to fail and then act accordingly: namely, terminate the Go routine so the runtime can kill its locked OS thread.
Visit() should never be called from the main Go routine, as any failure in switching namespaces leaves us with a tainted OS thread for the main Go routine. Yuk!
Types ¶
type InvalidNamespaceError ¶
type InvalidNamespaceError struct { Ref string // textual representation of a namespace reference. Err error // wrapped OS-level error. }
InvalidNamespaceError wraps an underlying OS-related error when dealing with Linux-kernel namespaces. Due to Golang's attempt at abstracting things, this might often be an os.PathError, in its turn wrapping a syscall error, such as syscall.EBADF, syscall.EINVAL, syscall.EPERM, et cetera.
func (*InvalidNamespaceError) Error ¶
func (e *InvalidNamespaceError) Error() string
Error returns a textual description of this invalid namespace error.
func (*InvalidNamespaceError) Unwrap ¶
func (e *InvalidNamespaceError) Unwrap() error
Unwrap returns the error underlying an invalid namespace error.
type NamespaceFd ¶
type NamespaceFd int
NamespaceFd references a Linux-kernel namespace via an open file descriptor. Following Unix tradition for file descriptors, NamespaceFd is an alias for an int (and not an uintptr, as in some cross-platform parts of the Golang packages). Please note that a NamespaceFd reference aliases a file descriptor, but it does not take ownership of it.
func (NamespaceFd) ID ¶
func (nsfd NamespaceFd) ID() (species.NamespaceID, error)
ID returns the namespace ID in form of its inode number of the Linux-kernel namespace referenced by this open file descriptor. Please be aware that ID even returns an inode number if the file descriptor doesn't reference a namespace but instead some other open file.
func (NamespaceFd) NsFd ¶
func (nsfd NamespaceFd) NsFd() (fd int, closer opener.FdCloser, err error)
NsFd returns an open file descriptor which references the namespace. After the file descriptor is no longer needed, the caller must call the returned close function, in order to avoid wasting file descriptors.
Please note that in case of a NamespaceFd reference, this returns the original open file descriptor (and doesn't make a copy of it). Aliasing a file descriptor into a NamespaceFd does not take ownership, so control of the lifetime of the aliased file descriptor is still up to its original creatorelations. In consequence, the closer returned for a namespace file descriptor will leave the original file descriptor untouched.
func (NamespaceFd) OpenTypedReference ¶
func (nsfd NamespaceFd) OpenTypedReference() (relations.Relation, opener.ReferenceCloser, error)
OpenTypedReference returns an open namespace reference, from which an OS-level file descriptor can be retrieved using NsFd(). OpenTypeReference is internally used to allow optimizing switching namespaces under the condition that additionally the type of namespace needs to be known at the same time.
func (NamespaceFd) OwnerUID ¶
func (nsfd NamespaceFd) OwnerUID() (int, error)
OwnerUID returns the user id (UID) of the user namespace referenced by this open file descriptor.
ℹ️ A Linux kernel version 4.11 or later is required.
func (NamespaceFd) Parent ¶
func (nsfd NamespaceFd) Parent() (relations.Relation, error)
Parent returns the parent namespace of the Linux-kernel namespace referenced by this open file descriptor. The namespace references must be either of type PID or user. For user namespaces, Parent() and User() behave identical.
ℹ️ A Linux kernel version 4.9 or later is required.
func (NamespaceFd) String ¶
func (nsfd NamespaceFd) String() string
String returns the textual representation for a namespace reference by file descriptor. This does contain only the file descriptor, but not the referenced namespace (ID), as we're here dealing with the references themselves.
func (NamespaceFd) Type ¶
func (nsfd NamespaceFd) Type() (species.NamespaceType, error)
Type returns the type of the Linux-kernel namespace referenced by this open file descriptor.
ℹ️ A Linux kernel version 4.11 or later is required.
func (NamespaceFd) User ¶
func (nsfd NamespaceFd) User() (relations.Relation, error)
User returns the owning user namespace the namespace referenced by this open file descriptor. The owning user namespace is returned in form of a NamespaceFile reference. For user namespaces, User() behaves identical to Parent().
ℹ️ A Linux kernel version 4.9 or later is required.
type NamespaceFile ¶
type NamespaceFile struct { // Please note that we embed(!) an os.File instead of embedding an os.File. // Our rationale here is that this is fine, as os.File has an indirection // designed in anyway in order to avoid users of os.File overwriting the // file descriptors. With this indirection in mind, we simply skip yet // another level of indirection, hopefully reducing pointer chasing. Hold my // beer! os.File }
NamespaceFile is an open os.File which references a Linux-kernel namespace. Please use NewNamespaceFile() to create a *NamespaceFile from an *os.File and an error (correctly deals with errors by returning a nil *NamespaceFile).
func NewNamespaceFile ¶
func NewNamespaceFile(f *os.File, err error) (*NamespaceFile, error)
NewNamespaceFile returns a new NamespaceFile given an *os.File and a nil error. In case of a non-nil error or of a nil *os.File it returns a nil *NamespaceFile instead, together with the error.
func (NamespaceFile) ID ¶
func (nsf NamespaceFile) ID() (species.NamespaceID, error)
ID returns the namespace ID in form of its inode number for any given Linux kernel namespace reference.
func (NamespaceFile) NsFd ¶
func (nsf NamespaceFile) NsFd() (int, opener.FdCloser, error)
NsFd returns a file descriptor referencing the namespace indicated in a namespace reference implementing the Opener interface.
⚠️ After the caller is done using the returned file descriptor, the caller must call the returned FdCloser function in order to properly release process resources. In case of any error when opening the referenced namespace, err will be non-nil, and might additionally wrap an underlying OS-level error.
⚠️ The caller must make sure that the namespace reference object doesn't get prematurely garbage collected, while the file descriptor returned by NsFd() is still in use.
func (NamespaceFile) OpenTypedReference ¶
func (nsf NamespaceFile) OpenTypedReference() (relations.Relation, opener.ReferenceCloser, error)
OpenTypedReference returns an open namespace reference, from which an OS-level file descriptor can be retrieved using NsFd(). OpenTypeReference is internally used to allow optimizing switching namespaces under the condition that additionally the type of namespace needs to be known at the same time.
func (NamespaceFile) OwnerUID ¶
func (nsf NamespaceFile) OwnerUID() (int, error)
OwnerUID returns the user id (UID) of the user namespace referenced by this open file descriptor.
ℹ️ A Linux kernel version 4.11 or later is required.
func (NamespaceFile) Parent ¶
func (nsf NamespaceFile) Parent() (relations.Relation, error)
Parent returns the parent namespace of a hierarchical namespaces, that is, of PID and user namespaces. For user namespaces, Parent() and User() behave identical.
ℹ️ A Linux kernel version 4.9 or later is required.
func (NamespaceFile) String ¶
func (nsf NamespaceFile) String() (s string)
String returns the textual representation for a namespace reference by file. This does contain only the os.File, but not the referenced namespace (ID), as we're here dealing with the references themselves.
func (NamespaceFile) Type ¶
func (nsf NamespaceFile) Type() (species.NamespaceType, error)
Type returns the type of the Linux-kernel namespace referenced by this open file.
ℹ️ A Linux kernel version 4.11 or later is required.
type NamespaceOperationError ¶
type NamespaceOperationError struct { InvalidNamespaceError Op string // failed namespace ioctl operation }
NamespaceOperationError wraps an invalid namespace operation, giving information about the failed operation both on a high level, as well as the underlying invalid namespace and OS-level errors.
func (*NamespaceOperationError) Error ¶
func (e *NamespaceOperationError) Error() string
Error returns a textual description of this invalid namespace error.
type NamespacePath ¶
type NamespacePath string
NamespacePath references a Linux-kernel namespace via a filesystem path.
func (NamespacePath) ID ¶
func (nsp NamespacePath) ID() (species.NamespaceID, error)
ID returns the namespace ID in form of its inode number for any given Linux kernel namespace reference.
func (NamespacePath) NsFd ¶
func (nsp NamespacePath) NsFd() (int, opener.FdCloser, error)
NsFd returns a file descriptor referencing the namespace indicated in a namespace reference implementing the Opener interface.
⚠️ After the caller is done using the returned file descriptor, the caller must call the returned FdCloser function in order to properly release process resources. In case of any error when opening the referenced namespace, err will be non-nil, and might additionally wrap an underlying OS-level error.
⚠️ The caller must make sure that the namespace reference object doesn't get prematurely garbage collected, while the file descriptor returned by NsFd() is still in use.
func (NamespacePath) OpenTypedReference ¶
func (nsp NamespacePath) OpenTypedReference() (relations.Relation, opener.ReferenceCloser, error)
OpenTypedReference returns an open namespace reference, from which an OS-level file descriptor can be retrieved using NsFd(). OpenTypeReference is internally used to allow optimizing switching namespaces under the condition that additionally the type of namespace needs to be known at the same time.
func (NamespacePath) OwnerUID ¶
func (nsp NamespacePath) OwnerUID() (int, error)
OwnerUID returns the user id (UID) of the user namespace referenced by this open file descriptor.
ℹ️ A Linux kernel version 4.11 or later is required.
func (NamespacePath) Parent ¶
func (nsp NamespacePath) Parent() (relations.Relation, error)
Parent returns the parent namespace of a hierarchical namespaces, that is, of PID and user namespaces. For user namespaces, Parent() and User() behave identical.
ℹ️ A Linux kernel version 4.9 or later is required.
func (NamespacePath) String ¶
func (nsp NamespacePath) String() string
String returns the textual representation for a namespace reference by file descriptor. This does contain only the file descriptor, but not the referenced namespace (ID), as we're here dealing with the references themselves.
func (NamespacePath) Type ¶
func (nsp NamespacePath) Type() (species.NamespaceType, error)
Type returns the type of the Linux-kernel namespace referenced by this file path.
ℹ️ A Linux kernel version 4.11 or later is required.
type TypedNamespaceFd ¶
type TypedNamespaceFd struct { NamespaceFd // underlying file descriptor referencing the namespace. // contains filtered or unexported fields }
TypedNamespaceFd references a Linux-kernel namespace via an open file descriptor.
func NewTypedNamespaceFd ¶
func NewTypedNamespaceFd(fd int, nstype species.NamespaceType) (*TypedNamespaceFd, error)
NewTypedNamespaceFd wraps a OS-level file descriptor referencing a Linux-kernel namespace, as well as the type of namespace. NewTypedNamespaceFd can be used in those situations where the type of namespace is already known, where later access to the type is of reference required and the namespace type query ioctl() is to be avoided (such as to support 4.9 to pre-4.11 Linux kernels).
func (*TypedNamespaceFd) OpenTypedReference ¶
func (nsfd *TypedNamespaceFd) OpenTypedReference() (relations.Relation, opener.ReferenceCloser, error)
OpenTypedReference returns an open namespace reference, from which an OS-level file descriptor can be retrieved using NsFd(). OpenTypeReference is internally used to allow optimizing switching namespaces under the condition that additionally the type of namespace needs to be known at the same time.
func (TypedNamespaceFd) String ¶
func (nsfd TypedNamespaceFd) String() string
String returns the textual representation for a typed namespace reference by file descriptor. This does contain only the type as well as the file descriptor, but not the referenced namespace (ID), as we're here dealing with the references themselves. If a dedicated reference was given at creation time (such as a filesystem path), then this is used instead of the fd number.
func (TypedNamespaceFd) Type ¶
func (nsfd TypedNamespaceFd) Type() (species.NamespaceType, error)
Type returns the foreknown type of the Linux-kernel namespace set when this namespace reference was created. This avoids having to call the corresponding namespace-type syscall, so it will work also on Linux kernels before 4.11, offering limited backward supported in those situations where the type of namespace is already known when establishing the namespace reference.
type TypedNamespaceFile ¶
type TypedNamespaceFile struct { NamespaceFile // contains filtered or unexported fields }
TypedNamespaceFile is a NamespaceFile (wrapping an open os.File) with a foreknown namespace type, optionally to be used in those use cases where the type of namespace referenced is known in advance. In such cases, ioctl() round trips to infer the type of namespace (when required) can be avoided, using the foreknown type instead.
func NewTypedNamespaceFile ¶
func NewTypedNamespaceFile(f *os.File, nstype species.NamespaceType) (*TypedNamespaceFile, error)
NewTypedNamespaceFile takes an open(!) os.File plus the type of namespace referenced and returns a new typed namespace reference object. If the namespace type is left zero, then this convenience helper will auto-detect it, unless when on a pre-4.11 kernel, where auto-detection is impossible due to the missing specific ioctl().
func (TypedNamespaceFile) NsFd ¶
func (nsf TypedNamespaceFile) NsFd() (int, opener.FdCloser, error)
NsFd returns a file descriptor referencing the namespace indicated in a namespace reference implementing the Opener interface.
⚠️ After the caller is done using the returned file descriptor, the caller must call the returned FdCloser function in order to properly release process resources. In case of any error when opening the referenced namespace, err will be non-nil, and might additionally wrap an underlying OS-level error.
⚠️ The caller must make sure that the namespace reference object doesn't get prematurely garbage collected, while the file descriptor returned by NsFd() is still in use.
func (TypedNamespaceFile) OpenTypedReference ¶
func (nsf TypedNamespaceFile) OpenTypedReference() (relations.Relation, opener.ReferenceCloser, error)
OpenTypedReference returns an open and typed namespace reference, from which an OS-level file descriptor can be retrieved using NsFd(). OpenTypeReference is internally used to allow optimizing switching namespaces under the condition that additionally the type of namespace needs to be known at the same time.
func (TypedNamespaceFile) Parent ¶
func (nsf TypedNamespaceFile) Parent() (relations.Relation, error)
Parent returns the parent namespace of a hierarchical namespaces, that is, of PID and user namespaces. For user namespaces, Parent() and User() behave identical.
ℹ️ A Linux kernel version 4.9 or later is required.
func (TypedNamespaceFile) Type ¶
func (nsf TypedNamespaceFile) Type() (species.NamespaceType, error)
Type returns the foreknown type of the Linux-kernel namespace set when this namespace reference was created. This avoids having to call the corresponding namespace-type syscall, so it will work also on Linux kernels before 4.11, offering limited backward supported in those situations where the type of namespace is already known when establishing the namespace reference.
type TypedNamespacePath ¶
type TypedNamespacePath struct { NamespacePath // contains filtered or unexported fields }
TypedNamespacePath is an explicitly typed NamespacePath reference in the file system. Use this type in case you (1) need to use Visit(), AND (2) must support kernels pre-4.11 which lack support for the NS_GET_NSTYPE ioctl(), AND (3) you know already the specific type of namespace. You may also use TypedNamespacePath when using Visit() on newer kernels to slightly optimize things, but this isn't strictly necessary.
ℹ️ Please note that User() and Parent() require a least a 4.9+ kernel. OwnerUID() requires at least a 4.11+ kernel.
func NewTypedNamespacePath ¶
func NewTypedNamespacePath(path string, nstype species.NamespaceType) *TypedNamespacePath
NewTypedNamespacePath returns a new explicitly typed namespace path reference.
func (TypedNamespacePath) OpenTypedReference ¶
func (nsp TypedNamespacePath) OpenTypedReference() (relations.Relation, opener.ReferenceCloser, error)
OpenTypedReference returns an open namespace reference, from which an OS-level file descriptor can be retrieved using NsFd(). OpenTypeReference is internally used to allow optimizing switching namespaces under the condition that additionally the type of namespace needs to be known at the same time.
func (TypedNamespacePath) Parent ¶
func (nsp TypedNamespacePath) Parent() (relations.Relation, error)
Parent returns the parent namespace of a hierarchical namespaces, that is, of PID and user namespaces. For user namespaces, Parent() and User() behave identical.
ℹ️ A Linux kernel version 4.9 or later is required.
func (TypedNamespacePath) String ¶
func (nsp TypedNamespacePath) String() string
String returns the textual representation for a namespace reference by file descriptor. This does contain only the file descriptor, but not the referenced namespace (ID), as we're here dealing with the references themselves.
func (TypedNamespacePath) Type ¶
func (nsp TypedNamespacePath) Type() (species.NamespaceType, error)
Type returns the foreknown type of the Linux-kernel namespace set when this namespace reference was created. This avoids having to call the corresponding namespace-type syscall, so it will work also on Linux kernels before 4.11, offering limited backward supported in those situations where the type of namespace is already known when establishing the namespace reference.
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
internal
|
|
opener
Package opener provides access to the file descriptors of namespace references.
|
Package opener provides access to the file descriptors of namespace references. |
Package mountineer allows accessing the file system contents from (other) mount namespaces via procfs.
|
Package mountineer allows accessing the file system contents from (other) mount namespaces via procfs. |
mntnssandbox
Package mntnssandbox is a single-purpose, stripped-down version of thediveo/gons.
|
Package mntnssandbox is a single-purpose, stripped-down version of thediveo/gons. |
Package portable provides so-called "portable" namespace references with validation and "locking" (keeping the referenced namespace open and thus alive).
|
Package portable provides so-called "portable" namespace references with validation and "locking" (keeping the referenced namespace open and thus alive). |
Package relations gives access to properties of and relationships between Linux-kernel namespaces, such as type and ID of a namespace, its owning user namespace, parent namespace in case of hierarchical namespaces, et cetera.
|
Package relations gives access to properties of and relationships between Linux-kernel namespaces, such as type and ID of a namespace, its owning user namespace, parent namespace in case of hierarchical namespaces, et cetera. |