mirror of
https://github.com/tailscale/tailscale.git
synced 2025-12-15 20:12:04 +00:00
cmd/k8s-operator,k8s-operator,kube: Add TSRecorder CRD + controller (#13299)
cmd/k8s-operator,k8s-operator,kube: Add TSRecorder CRD + controller Deploys tsrecorder images to the operator's cluster. S3 storage is configured via environment variables from a k8s Secret. Currently only supports a single tsrecorder replica, but I've tried to take early steps towards supporting multiple replicas by e.g. having a separate secret for auth and state storage. Example CR: ```yaml apiVersion: tailscale.com/v1alpha1 kind: Recorder metadata: name: rec spec: enableUI: true ``` Updates #13298 Signed-off-by: Tom Proctor <tomhjp@users.noreply.github.com>
This commit is contained in:
@@ -49,7 +49,16 @@ func init() {
|
||||
|
||||
// Adds the list of known types to api.Scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion, &Connector{}, &ConnectorList{}, &ProxyClass{}, &ProxyClassList{}, &DNSConfig{}, &DNSConfigList{})
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&Connector{},
|
||||
&ConnectorList{},
|
||||
&ProxyClass{},
|
||||
&ProxyClassList{},
|
||||
&DNSConfig{},
|
||||
&DNSConfigList{},
|
||||
&Recorder{},
|
||||
&RecorderList{},
|
||||
)
|
||||
|
||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
return nil
|
||||
|
||||
@@ -173,4 +173,5 @@ const (
|
||||
ConnectorReady ConditionType = `ConnectorReady`
|
||||
ProxyClassready ConditionType = `ProxyClassReady`
|
||||
ProxyReady ConditionType = `TailscaleProxyReady` // a Tailscale-specific condition type for corev1.Service
|
||||
RecorderReady ConditionType = `RecorderReady`
|
||||
)
|
||||
|
||||
249
k8s-operator/apis/v1alpha1/types_recorder.go
Normal file
249
k8s-operator/apis/v1alpha1/types_recorder.go
Normal file
@@ -0,0 +1,249 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !plan9
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:resource:scope=Cluster,shortName=rec
|
||||
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=`.status.conditions[?(@.type == "RecorderReady")].reason`,description="Status of the deployed Recorder resources."
|
||||
// +kubebuilder:printcolumn:name="URL",type="string",JSONPath=`.status.devices[?(@.url != "")].url`,description="URL on which the UI is exposed if enabled."
|
||||
|
||||
type Recorder struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// Spec describes the desired recorder instance.
|
||||
Spec RecorderSpec `json:"spec"`
|
||||
|
||||
// RecorderStatus describes the status of the recorder. This is set
|
||||
// and managed by the Tailscale operator.
|
||||
// +optional
|
||||
Status RecorderStatus `json:"status"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
|
||||
type RecorderList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata"`
|
||||
|
||||
Items []Recorder `json:"items"`
|
||||
}
|
||||
|
||||
type RecorderSpec struct {
|
||||
// Configuration parameters for the Recorder's StatefulSet. The operator
|
||||
// deploys a StatefulSet for each Recorder resource.
|
||||
// +optional
|
||||
StatefulSet RecorderStatefulSet `json:"statefulSet"`
|
||||
|
||||
// Tags that the Tailscale device will be tagged with. Defaults to [tag:k8s].
|
||||
// If you specify custom tags here, make sure you also make the operator
|
||||
// an owner of these tags.
|
||||
// See https://tailscale.com/kb/1236/kubernetes-operator/#setting-up-the-kubernetes-operator.
|
||||
// Tags cannot be changed once a Recorder node has been created.
|
||||
// Tag values must be in form ^tag:[a-zA-Z][a-zA-Z0-9-]*$.
|
||||
// +optional
|
||||
Tags Tags `json:"tags,omitempty"`
|
||||
|
||||
// TODO(tomhjp): Support a hostname or hostname prefix field, depending on
|
||||
// the plan for multiple replicas.
|
||||
|
||||
// Set to true to enable the Recorder UI. The UI lists and plays recorded sessions.
|
||||
// The UI will be served at <MagicDNS name of the recorder>:443. Defaults to false.
|
||||
// Corresponds to --ui tsrecorder flag https://tailscale.com/kb/1246/tailscale-ssh-session-recording#deploy-a-recorder-node.
|
||||
// Required if S3 storage is not set up, to ensure that recordings are accessible.
|
||||
// +optional
|
||||
EnableUI bool `json:"enableUI,omitempty"`
|
||||
|
||||
// Configure where to store session recordings. By default, recordings will
|
||||
// be stored in a local ephemeral volume, and will not be persisted past the
|
||||
// lifetime of a specific pod.
|
||||
// +optional
|
||||
Storage Storage `json:"storage,omitempty"`
|
||||
}
|
||||
|
||||
type RecorderStatefulSet struct {
|
||||
// Labels that will be added to the StatefulSet created for the Recorder.
|
||||
// Any labels specified here will be merged with the default labels applied
|
||||
// to the StatefulSet by the operator.
|
||||
// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#syntax-and-character-set
|
||||
// +optional
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
|
||||
// Annotations that will be added to the StatefulSet created for the Recorder.
|
||||
// Any Annotations specified here will be merged with the default annotations
|
||||
// applied to the StatefulSet by the operator.
|
||||
// https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/#syntax-and-character-set
|
||||
// +optional
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
|
||||
// Configuration for pods created by the Recorder's StatefulSet.
|
||||
// +optional
|
||||
Pod RecorderPod `json:"pod,omitempty"`
|
||||
}
|
||||
|
||||
type RecorderPod struct {
|
||||
// Labels that will be added to Recorder Pods. Any labels specified here
|
||||
// will be merged with the default labels applied to the Pod by the operator.
|
||||
// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#syntax-and-character-set
|
||||
// +optional
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
|
||||
// Annotations that will be added to Recorder Pods. Any annotations
|
||||
// specified here will be merged with the default annotations applied to
|
||||
// the Pod by the operator.
|
||||
// https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/#syntax-and-character-set
|
||||
// +optional
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
|
||||
// Affinity rules for Recorder Pods. By default, the operator does not
|
||||
// apply any affinity rules.
|
||||
// https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#affinity
|
||||
// +optional
|
||||
Affinity *corev1.Affinity `json:"affinity,omitempty"`
|
||||
|
||||
// Configuration for the Recorder container running tailscale.
|
||||
// +optional
|
||||
Container RecorderContainer `json:"container,omitempty"`
|
||||
|
||||
// Security context for Recorder Pods. By default, the operator does not
|
||||
// apply any Pod security context.
|
||||
// https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#security-context-2
|
||||
// +optional
|
||||
SecurityContext *corev1.PodSecurityContext `json:"securityContext,omitempty"`
|
||||
|
||||
// Image pull Secrets for Recorder Pods.
|
||||
// https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#PodSpec
|
||||
// +optional
|
||||
ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"`
|
||||
|
||||
// Node selector rules for Recorder Pods. By default, the operator does
|
||||
// not apply any node selector rules.
|
||||
// https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#scheduling
|
||||
// +optional
|
||||
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
|
||||
|
||||
// Tolerations for Recorder Pods. By default, the operator does not apply
|
||||
// any tolerations.
|
||||
// https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#scheduling
|
||||
// +optional
|
||||
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
|
||||
}
|
||||
|
||||
type RecorderContainer struct {
|
||||
// List of environment variables to set in the container.
|
||||
// https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#environment-variables
|
||||
// Note that environment variables provided here will take precedence
|
||||
// over Tailscale-specific environment variables set by the operator,
|
||||
// however running proxies with custom values for Tailscale environment
|
||||
// variables (i.e TS_USERSPACE) is not recommended and might break in
|
||||
// the future.
|
||||
// +optional
|
||||
Env []Env `json:"env,omitempty"`
|
||||
|
||||
// Container image name including tag. Defaults to docker.io/tailscale/tsrecorder
|
||||
// with the same tag as the operator, but the official images are also
|
||||
// available at ghcr.io/tailscale/tsrecorder.
|
||||
// https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#image
|
||||
// +optional
|
||||
Image string `json:"image,omitempty"`
|
||||
|
||||
// Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always.
|
||||
// https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#image
|
||||
// +kubebuilder:validation:Enum=Always;Never;IfNotPresent
|
||||
// +optional
|
||||
ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"`
|
||||
|
||||
// Container resource requirements.
|
||||
// By default, the operator does not apply any resource requirements. The
|
||||
// amount of resources required wil depend on the volume of recordings sent.
|
||||
// https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#resources
|
||||
// +optional
|
||||
Resources corev1.ResourceRequirements `json:"resources,omitempty"`
|
||||
|
||||
// Container security context. By default, the operator does not apply any
|
||||
// container security context.
|
||||
// https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#security-context
|
||||
// +optional
|
||||
SecurityContext *corev1.SecurityContext `json:"securityContext,omitempty"`
|
||||
}
|
||||
|
||||
type Storage struct {
|
||||
// Configure an S3-compatible API for storage. Required if the UI is not
|
||||
// enabled, to ensure that recordings are accessible.
|
||||
// +optional
|
||||
S3 *S3 `json:"s3,omitempty"`
|
||||
}
|
||||
|
||||
type S3 struct {
|
||||
// S3-compatible endpoint, e.g. s3.us-east-1.amazonaws.com.
|
||||
Endpoint string `json:"endpoint,omitempty"`
|
||||
|
||||
// Bucket name to write to. The bucket is expected to be used solely for
|
||||
// recordings, as there is no stable prefix for written object names.
|
||||
Bucket string `json:"bucket,omitempty"`
|
||||
|
||||
// Configure environment variable credentials for managing objects in the
|
||||
// configured bucket. If not set, tsrecorder will try to acquire credentials
|
||||
// first from the file system and then the STS API.
|
||||
// +optional
|
||||
Credentials S3Credentials `json:"credentials,omitempty"`
|
||||
}
|
||||
|
||||
type S3Credentials struct {
|
||||
// Use a Kubernetes Secret from the operator's namespace as the source of
|
||||
// credentials.
|
||||
// +optional
|
||||
Secret S3Secret `json:"secret,omitempty"`
|
||||
}
|
||||
|
||||
type S3Secret struct {
|
||||
// The name of a Kubernetes Secret in the operator's namespace that contains
|
||||
// credentials for writing to the configured bucket. Each key-value pair
|
||||
// from the secret's data will be mounted as an environment variable. It
|
||||
// should include keys for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY if
|
||||
// using a static access key.
|
||||
//+optional
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
type RecorderStatus struct {
|
||||
// List of status conditions to indicate the status of the Recorder.
|
||||
// Known condition types are `RecorderReady`.
|
||||
// +listType=map
|
||||
// +listMapKey=type
|
||||
// +optional
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty"`
|
||||
|
||||
// List of tailnet devices associated with the Recorder statefulset.
|
||||
// +listType=map
|
||||
// +listMapKey=hostname
|
||||
// +optional
|
||||
Devices []TailnetDevice `json:"devices,omitempty"`
|
||||
}
|
||||
|
||||
type TailnetDevice struct {
|
||||
// Hostname is the fully qualified domain name of the device.
|
||||
// If MagicDNS is enabled in your tailnet, it is the MagicDNS name of the
|
||||
// node.
|
||||
Hostname string `json:"hostname"`
|
||||
|
||||
// TailnetIPs is the set of tailnet IP addresses (both IPv4 and IPv6)
|
||||
// assigned to the device.
|
||||
// +optional
|
||||
TailnetIPs []string `json:"tailnetIPs,omitempty"`
|
||||
|
||||
// URL where the UI is available if enabled for replaying recordings. This
|
||||
// will be an HTTPS MagicDNS URL. You must be connected to the same tailnet
|
||||
// as the recorder to access it.
|
||||
// +optional
|
||||
URL string `json:"url,omitempty"`
|
||||
}
|
||||
@@ -78,16 +78,16 @@ type DNSConfigSpec struct {
|
||||
}
|
||||
|
||||
type Nameserver struct {
|
||||
// Nameserver image.
|
||||
// Nameserver image. Defaults to tailscale/k8s-nameserver:unstable.
|
||||
// +optional
|
||||
Image *Image `json:"image,omitempty"`
|
||||
Image *NameserverImage `json:"image,omitempty"`
|
||||
}
|
||||
|
||||
type Image struct {
|
||||
type NameserverImage struct {
|
||||
// Repo defaults to tailscale/k8s-nameserver.
|
||||
// +optional
|
||||
Repo string `json:"repo,omitempty"`
|
||||
// Tag defaults to operator's own tag.
|
||||
// Tag defaults to unstable.
|
||||
// +optional
|
||||
Tag string `json:"tag,omitempty"`
|
||||
}
|
||||
|
||||
@@ -271,21 +271,6 @@ func (in *Env) DeepCopy() *Env {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Image) DeepCopyInto(out *Image) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Image.
|
||||
func (in *Image) DeepCopy() *Image {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Image)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Metrics) DeepCopyInto(out *Metrics) {
|
||||
*out = *in
|
||||
@@ -306,7 +291,7 @@ func (in *Nameserver) DeepCopyInto(out *Nameserver) {
|
||||
*out = *in
|
||||
if in.Image != nil {
|
||||
in, out := &in.Image, &out.Image
|
||||
*out = new(Image)
|
||||
*out = new(NameserverImage)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
@@ -321,6 +306,21 @@ func (in *Nameserver) DeepCopy() *Nameserver {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NameserverImage) DeepCopyInto(out *NameserverImage) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NameserverImage.
|
||||
func (in *NameserverImage) DeepCopy() *NameserverImage {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(NameserverImage)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NameserverStatus) DeepCopyInto(out *NameserverStatus) {
|
||||
*out = *in
|
||||
@@ -515,6 +515,231 @@ func (in *ProxyClassStatus) DeepCopy() *ProxyClassStatus {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Recorder) DeepCopyInto(out *Recorder) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Recorder.
|
||||
func (in *Recorder) DeepCopy() *Recorder {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Recorder)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Recorder) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RecorderContainer) DeepCopyInto(out *RecorderContainer) {
|
||||
*out = *in
|
||||
if in.Env != nil {
|
||||
in, out := &in.Env, &out.Env
|
||||
*out = make([]Env, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
in.Resources.DeepCopyInto(&out.Resources)
|
||||
if in.SecurityContext != nil {
|
||||
in, out := &in.SecurityContext, &out.SecurityContext
|
||||
*out = new(corev1.SecurityContext)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RecorderContainer.
|
||||
func (in *RecorderContainer) DeepCopy() *RecorderContainer {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RecorderContainer)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RecorderList) DeepCopyInto(out *RecorderList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Recorder, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RecorderList.
|
||||
func (in *RecorderList) DeepCopy() *RecorderList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RecorderList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *RecorderList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RecorderPod) DeepCopyInto(out *RecorderPod) {
|
||||
*out = *in
|
||||
if in.Labels != nil {
|
||||
in, out := &in.Labels, &out.Labels
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.Annotations != nil {
|
||||
in, out := &in.Annotations, &out.Annotations
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.Affinity != nil {
|
||||
in, out := &in.Affinity, &out.Affinity
|
||||
*out = new(corev1.Affinity)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
in.Container.DeepCopyInto(&out.Container)
|
||||
if in.SecurityContext != nil {
|
||||
in, out := &in.SecurityContext, &out.SecurityContext
|
||||
*out = new(corev1.PodSecurityContext)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.ImagePullSecrets != nil {
|
||||
in, out := &in.ImagePullSecrets, &out.ImagePullSecrets
|
||||
*out = make([]corev1.LocalObjectReference, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.NodeSelector != nil {
|
||||
in, out := &in.NodeSelector, &out.NodeSelector
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.Tolerations != nil {
|
||||
in, out := &in.Tolerations, &out.Tolerations
|
||||
*out = make([]corev1.Toleration, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RecorderPod.
|
||||
func (in *RecorderPod) DeepCopy() *RecorderPod {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RecorderPod)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RecorderSpec) DeepCopyInto(out *RecorderSpec) {
|
||||
*out = *in
|
||||
in.StatefulSet.DeepCopyInto(&out.StatefulSet)
|
||||
if in.Tags != nil {
|
||||
in, out := &in.Tags, &out.Tags
|
||||
*out = make(Tags, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
in.Storage.DeepCopyInto(&out.Storage)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RecorderSpec.
|
||||
func (in *RecorderSpec) DeepCopy() *RecorderSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RecorderSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RecorderStatefulSet) DeepCopyInto(out *RecorderStatefulSet) {
|
||||
*out = *in
|
||||
if in.Labels != nil {
|
||||
in, out := &in.Labels, &out.Labels
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.Annotations != nil {
|
||||
in, out := &in.Annotations, &out.Annotations
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
in.Pod.DeepCopyInto(&out.Pod)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RecorderStatefulSet.
|
||||
func (in *RecorderStatefulSet) DeepCopy() *RecorderStatefulSet {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RecorderStatefulSet)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RecorderStatus) DeepCopyInto(out *RecorderStatus) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]v1.Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Devices != nil {
|
||||
in, out := &in.Devices, &out.Devices
|
||||
*out = make([]TailnetDevice, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RecorderStatus.
|
||||
func (in *RecorderStatus) DeepCopy() *RecorderStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RecorderStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in Routes) DeepCopyInto(out *Routes) {
|
||||
{
|
||||
@@ -534,6 +759,53 @@ func (in Routes) DeepCopy() Routes {
|
||||
return *out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *S3) DeepCopyInto(out *S3) {
|
||||
*out = *in
|
||||
out.Credentials = in.Credentials
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S3.
|
||||
func (in *S3) DeepCopy() *S3 {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(S3)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *S3Credentials) DeepCopyInto(out *S3Credentials) {
|
||||
*out = *in
|
||||
out.Secret = in.Secret
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S3Credentials.
|
||||
func (in *S3Credentials) DeepCopy() *S3Credentials {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(S3Credentials)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *S3Secret) DeepCopyInto(out *S3Secret) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S3Secret.
|
||||
func (in *S3Secret) DeepCopy() *S3Secret {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(S3Secret)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *StatefulSet) DeepCopyInto(out *StatefulSet) {
|
||||
*out = *in
|
||||
@@ -568,6 +840,26 @@ func (in *StatefulSet) DeepCopy() *StatefulSet {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Storage) DeepCopyInto(out *Storage) {
|
||||
*out = *in
|
||||
if in.S3 != nil {
|
||||
in, out := &in.S3, &out.S3
|
||||
*out = new(S3)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Storage.
|
||||
func (in *Storage) DeepCopy() *Storage {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Storage)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SubnetRouter) DeepCopyInto(out *SubnetRouter) {
|
||||
*out = *in
|
||||
@@ -607,6 +899,26 @@ func (in Tags) DeepCopy() Tags {
|
||||
return *out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TailnetDevice) DeepCopyInto(out *TailnetDevice) {
|
||||
*out = *in
|
||||
if in.TailnetIPs != nil {
|
||||
in, out := &in.TailnetIPs, &out.TailnetIPs
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TailnetDevice.
|
||||
func (in *TailnetDevice) DeepCopy() *TailnetDevice {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TailnetDevice)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TailscaleConfig) DeepCopyInto(out *TailscaleConfig) {
|
||||
*out = *in
|
||||
|
||||
Reference in New Issue
Block a user