mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-25 19:15:34 +00:00
cmd/k8s-operator,k8s-opeerator: include Connector's MagicDNS name and tailnet IPs in status (#12359)
Add new fields TailnetIPs and Hostname to Connector Status. These contain the addresses of the Tailscale node that the operator created for the Connector to aid debugging. Fixes #12214 Signed-off-by: Tom Proctor <tomhjp@users.noreply.github.com>
This commit is contained in:
parent
3a6d3f1a5b
commit
23e26e589f
@ -108,7 +108,7 @@ func (a *ConnectorReconciler) Reconcile(ctx context.Context, req reconcile.Reque
|
|||||||
}
|
}
|
||||||
|
|
||||||
oldCnStatus := cn.Status.DeepCopy()
|
oldCnStatus := cn.Status.DeepCopy()
|
||||||
setStatus := func(cn *tsapi.Connector, conditionType tsapi.ConnectorConditionType, status metav1.ConditionStatus, reason, message string) (reconcile.Result, error) {
|
setStatus := func(cn *tsapi.Connector, _ tsapi.ConnectorConditionType, status metav1.ConditionStatus, reason, message string) (reconcile.Result, error) {
|
||||||
tsoperator.SetConnectorCondition(cn, tsapi.ConnectorReady, status, reason, message, cn.Generation, a.clock, logger)
|
tsoperator.SetConnectorCondition(cn, tsapi.ConnectorReady, status, reason, message, cn.Generation, a.clock, logger)
|
||||||
if !apiequality.Semantic.DeepEqual(oldCnStatus, cn.Status) {
|
if !apiequality.Semantic.DeepEqual(oldCnStatus, cn.Status) {
|
||||||
// An error encountered here should get returned by the Reconcile function.
|
// An error encountered here should get returned by the Reconcile function.
|
||||||
@ -211,7 +211,27 @@ func (a *ConnectorReconciler) maybeProvisionConnector(ctx context.Context, logge
|
|||||||
gaugeConnectorResources.Set(int64(connectors.Len()))
|
gaugeConnectorResources.Set(int64(connectors.Len()))
|
||||||
|
|
||||||
_, err := a.ssr.Provision(ctx, logger, sts)
|
_, err := a.ssr.Provision(ctx, logger, sts)
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, tsHost, ips, err := a.ssr.DeviceInfo(ctx, crl)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if tsHost == "" {
|
||||||
|
logger.Debugf("no Tailscale hostname known yet, waiting for connector pod to finish auth")
|
||||||
|
// No hostname yet. Wait for the connector pod to auth.
|
||||||
|
cn.Status.TailnetIPs = nil
|
||||||
|
cn.Status.Hostname = ""
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cn.Status.TailnetIPs = ips
|
||||||
|
cn.Status.Hostname = tsHost
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ConnectorReconciler) maybeCleanupConnector(ctx context.Context, logger *zap.SugaredLogger, cn *tsapi.Connector) (bool, error) {
|
func (a *ConnectorReconciler) maybeCleanupConnector(ctx context.Context, logger *zap.SugaredLogger, cn *tsapi.Connector) (bool, error) {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||||
tsapi "tailscale.com/k8s-operator/apis/v1alpha1"
|
tsapi "tailscale.com/k8s-operator/apis/v1alpha1"
|
||||||
"tailscale.com/tstest"
|
"tailscale.com/tstest"
|
||||||
|
"tailscale.com/util/mak"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConnector(t *testing.T) {
|
func TestConnector(t *testing.T) {
|
||||||
@ -29,7 +30,7 @@ func TestConnector(t *testing.T) {
|
|||||||
},
|
},
|
||||||
TypeMeta: metav1.TypeMeta{
|
TypeMeta: metav1.TypeMeta{
|
||||||
Kind: tsapi.ConnectorKind,
|
Kind: tsapi.ConnectorKind,
|
||||||
APIVersion: "tailscale.io/v1alpha1",
|
APIVersion: "tailscale.com/v1alpha1",
|
||||||
},
|
},
|
||||||
Spec: tsapi.ConnectorSpec{
|
Spec: tsapi.ConnectorSpec{
|
||||||
SubnetRouter: &tsapi.SubnetRouter{
|
SubnetRouter: &tsapi.SubnetRouter{
|
||||||
@ -77,6 +78,23 @@ func TestConnector(t *testing.T) {
|
|||||||
expectEqual(t, fc, expectedSecret(t, opts), nil)
|
expectEqual(t, fc, expectedSecret(t, opts), nil)
|
||||||
expectEqual(t, fc, expectedSTS(t, fc, opts), removeHashAnnotation)
|
expectEqual(t, fc, expectedSTS(t, fc, opts), removeHashAnnotation)
|
||||||
|
|
||||||
|
// Connector status should get updated with the IP/hostname info when available.
|
||||||
|
const hostname = "foo.tailnetxyz.ts.net"
|
||||||
|
mustUpdate(t, fc, "operator-ns", opts.secretName, func(secret *corev1.Secret) {
|
||||||
|
mak.Set(&secret.Data, "device_id", []byte("1234"))
|
||||||
|
mak.Set(&secret.Data, "device_fqdn", []byte(hostname))
|
||||||
|
mak.Set(&secret.Data, "device_ips", []byte(`["127.0.0.1", "::1"]`))
|
||||||
|
})
|
||||||
|
expectReconciled(t, cr, "", "test")
|
||||||
|
cn.Finalizers = append(cn.Finalizers, "tailscale.com/finalizer")
|
||||||
|
cn.Status.IsExitNode = cn.Spec.ExitNode
|
||||||
|
cn.Status.SubnetRoutes = cn.Spec.SubnetRouter.AdvertiseRoutes.Stringify()
|
||||||
|
cn.Status.Hostname = hostname
|
||||||
|
cn.Status.TailnetIPs = []string{"127.0.0.1", "::1"}
|
||||||
|
expectEqual(t, fc, cn, func(o *tsapi.Connector) {
|
||||||
|
o.Status.Conditions = nil
|
||||||
|
})
|
||||||
|
|
||||||
// Add another route to be advertised.
|
// Add another route to be advertised.
|
||||||
mustUpdate[tsapi.Connector](t, fc, "", "test", func(conn *tsapi.Connector) {
|
mustUpdate[tsapi.Connector](t, fc, "", "test", func(conn *tsapi.Connector) {
|
||||||
conn.Spec.SubnetRouter.AdvertiseRoutes = []tsapi.Route{"10.40.0.0/14", "10.44.0.0/20"}
|
conn.Spec.SubnetRouter.AdvertiseRoutes = []tsapi.Route{"10.40.0.0/14", "10.44.0.0/20"}
|
||||||
|
@ -117,12 +117,20 @@ spec:
|
|||||||
x-kubernetes-list-map-keys:
|
x-kubernetes-list-map-keys:
|
||||||
- type
|
- type
|
||||||
x-kubernetes-list-type: map
|
x-kubernetes-list-type: map
|
||||||
|
hostname:
|
||||||
|
description: Hostname is the fully qualified domain name of the Connector node. If MagicDNS is enabled in your tailnet, it is the MagicDNS name of the node.
|
||||||
|
type: string
|
||||||
isExitNode:
|
isExitNode:
|
||||||
description: IsExitNode is set to true if the Connector acts as an exit node.
|
description: IsExitNode is set to true if the Connector acts as an exit node.
|
||||||
type: boolean
|
type: boolean
|
||||||
subnetRoutes:
|
subnetRoutes:
|
||||||
description: SubnetRoutes are the routes currently exposed to tailnet via this Connector instance.
|
description: SubnetRoutes are the routes currently exposed to tailnet via this Connector instance.
|
||||||
type: string
|
type: string
|
||||||
|
tailnetIPs:
|
||||||
|
description: TailnetIPs is the set of tailnet IP addresses (both IPv4 and IPv6) assigned to the Connector node.
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
served: true
|
served: true
|
||||||
storage: true
|
storage: true
|
||||||
subresources:
|
subresources:
|
||||||
|
@ -142,12 +142,20 @@ spec:
|
|||||||
x-kubernetes-list-map-keys:
|
x-kubernetes-list-map-keys:
|
||||||
- type
|
- type
|
||||||
x-kubernetes-list-type: map
|
x-kubernetes-list-type: map
|
||||||
|
hostname:
|
||||||
|
description: Hostname is the fully qualified domain name of the Connector node. If MagicDNS is enabled in your tailnet, it is the MagicDNS name of the node.
|
||||||
|
type: string
|
||||||
isExitNode:
|
isExitNode:
|
||||||
description: IsExitNode is set to true if the Connector acts as an exit node.
|
description: IsExitNode is set to true if the Connector acts as an exit node.
|
||||||
type: boolean
|
type: boolean
|
||||||
subnetRoutes:
|
subnetRoutes:
|
||||||
description: SubnetRoutes are the routes currently exposed to tailnet via this Connector instance.
|
description: SubnetRoutes are the routes currently exposed to tailnet via this Connector instance.
|
||||||
type: string
|
type: string
|
||||||
|
tailnetIPs:
|
||||||
|
description: TailnetIPs is the set of tailnet IP addresses (both IPv4 and IPv6) assigned to the Connector node.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- spec
|
- spec
|
||||||
|
@ -178,6 +178,13 @@ ConnectorStatus describes the status of the Connector. This is set and managed b
|
|||||||
List of status conditions to indicate the status of the Connector. Known condition types are `ConnectorReady`.<br/>
|
List of status conditions to indicate the status of the Connector. Known condition types are `ConnectorReady`.<br/>
|
||||||
</td>
|
</td>
|
||||||
<td>false</td>
|
<td>false</td>
|
||||||
|
</tr><tr>
|
||||||
|
<td><b>hostname</b></td>
|
||||||
|
<td>string</td>
|
||||||
|
<td>
|
||||||
|
Hostname is the fully qualified domain name of the Connector node. If MagicDNS is enabled in your tailnet, it is the MagicDNS name of the node.<br/>
|
||||||
|
</td>
|
||||||
|
<td>false</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><b>isExitNode</b></td>
|
<td><b>isExitNode</b></td>
|
||||||
<td>boolean</td>
|
<td>boolean</td>
|
||||||
@ -192,6 +199,13 @@ ConnectorStatus describes the status of the Connector. This is set and managed b
|
|||||||
SubnetRoutes are the routes currently exposed to tailnet via this Connector instance.<br/>
|
SubnetRoutes are the routes currently exposed to tailnet via this Connector instance.<br/>
|
||||||
</td>
|
</td>
|
||||||
<td>false</td>
|
<td>false</td>
|
||||||
|
</tr><tr>
|
||||||
|
<td><b>tailnetIPs</b></td>
|
||||||
|
<td>[]string</td>
|
||||||
|
<td>
|
||||||
|
TailnetIPs is the set of tailnet IP addresses (both IPv4 and IPv6) assigned to the Connector node.<br/>
|
||||||
|
</td>
|
||||||
|
<td>false</td>
|
||||||
</tr></tbody>
|
</tr></tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@ -156,6 +156,15 @@ type ConnectorStatus struct {
|
|||||||
// IsExitNode is set to true if the Connector acts as an exit node.
|
// IsExitNode is set to true if the Connector acts as an exit node.
|
||||||
// +optional
|
// +optional
|
||||||
IsExitNode bool `json:"isExitNode"`
|
IsExitNode bool `json:"isExitNode"`
|
||||||
|
// TailnetIPs is the set of tailnet IP addresses (both IPv4 and IPv6)
|
||||||
|
// assigned to the Connector node.
|
||||||
|
// +optional
|
||||||
|
TailnetIPs []string `json:"tailnetIPs,omitempty"`
|
||||||
|
// Hostname is the fully qualified domain name of the Connector node.
|
||||||
|
// If MagicDNS is enabled in your tailnet, it is the MagicDNS name of the
|
||||||
|
// node.
|
||||||
|
// +optional
|
||||||
|
Hostname string `json:"hostname,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnectorCondition contains condition information for a Connector.
|
// ConnectorCondition contains condition information for a Connector.
|
||||||
|
@ -125,6 +125,11 @@ func (in *ConnectorStatus) DeepCopyInto(out *ConnectorStatus) {
|
|||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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 ConnectorStatus.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConnectorStatus.
|
||||||
|
Loading…
Reference in New Issue
Block a user