Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support manage single node #767

Merged
merged 1 commit into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ jobs:
case:
- kwok
- kwok-with-cni
- kwok-single-node
continue-on-error: false
runs-on: ubuntu-latest
steps:
Expand Down
1 change: 1 addition & 0 deletions kustomize/kwok/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ spec:
- --manage-all-nodes=false
- --manage-nodes-with-annotation-selector=kwok.x-k8s.io/node=fake
- --manage-nodes-with-label-selector=
- --manage-single-node=
- --disregard-status-with-annotation-selector=kwok.x-k8s.io/status=custom
- --disregard-status-with-label-selector=
- --node-ip=$(POD_IP)
Expand Down
18 changes: 16 additions & 2 deletions pkg/apis/config/v1alpha1/kwok_configuration_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,33 @@ type KwokConfigurationOptions struct {
// is the default value for flag --tls-private-key-file
TLSPrivateKeyFile string `json:"tlsPrivateKeyFile,omitempty"`

// ManageSingleNode is the option to manage a single node name.
// is the default value for flag --manage-single-node
// Note: when `manage-all-nodes` is specified as true or
// `manage-nodes-with-label-selector` or `manage-nodes-with-annotation-selector` is specified,
// this is a no-op.
ManageSingleNode string `json:"manageSingleNode,omitempty"`

// Default option to manage (i.e., maintain heartbeat/liveness of) all Nodes or not.
// is the default value for flag --manage-all-nodes
// Note: when `manage-single-node` is specified as true or
// `manage-nodes-with-label-selector` or `manage-nodes-with-annotation-selector` is specified,
// this is a no-op.
// +default=false
ManageAllNodes *bool `json:"manageAllNodes,omitempty"`

// Default annotations specified on Nodes to demand manage.
// Note: when `all-node-manage` is specified as true, this is a no-op.
// is the default value for flag --manage-nodes-with-annotation-selector
// Note: when `all-node-manage` is specified as true or
// `manage-single-node` is specified,
// this is a no-op.
ManageNodesWithAnnotationSelector string `json:"manageNodesWithAnnotationSelector,omitempty"`

// Default labels specified on Nodes to demand manage.
// Note: when `all-node-manage` is specified as true, this is a no-op.
// is the default value for flag --manage-nodes-with-label-selector
// Note: when `all-node-manage` is specified as true or
// `manage-single-node` is specified,
// this is a no-op.
ManageNodesWithLabelSelector string `json:"manageNodesWithLabelSelector,omitempty"`

// If a Node/Pod is on a managed Node and has this annotation status will not be modified
Expand Down
7 changes: 5 additions & 2 deletions pkg/apis/internalversion/kwok_configuration_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ type KwokConfigurationOptions struct {
// TLSPrivateKeyFile is the ile containing x509 private key
TLSPrivateKeyFile string

// ManageSingleNode is the option to manage a single node name
ManageSingleNode string

// Default option to manage (i.e., maintain heartbeat/liveness of) all Nodes or not.
ManageAllNodes bool

Expand All @@ -74,11 +77,11 @@ type KwokConfigurationOptions struct {
// Experimental support for getting pod ip from CNI, for CNI-related components, Only works with Linux.
EnableCNI bool

// enableDebuggingHandlers enables server endpoints for log collection
// EnableDebuggingHandlers enables server endpoints for log collection
// and local running of containers and commands
EnableDebuggingHandlers bool

// enableContentionProfiling enables lock contention profiling, if enableDebuggingHandlers is true.
// EnableContentionProfiling enables lock contention profiling, if enableDebuggingHandlers is true.
EnableContentionProfiling bool

// EnableProfiling enables /debug/pprof handler.
Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/internalversion/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 17 additions & 14 deletions pkg/kwok/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,10 @@ func NewCommand(ctx context.Context) *cobra.Command {
cmd.Flags().IntVar(&flags.Options.NodePort, "node-port", flags.Options.NodePort, "Port of the node")
cmd.Flags().StringVar(&flags.Options.TLSCertFile, "tls-cert-file", flags.Options.TLSCertFile, "File containing the default x509 Certificate for HTTPS")
cmd.Flags().StringVar(&flags.Options.TLSPrivateKeyFile, "tls-private-key-file", flags.Options.TLSPrivateKeyFile, "File containing the default x509 private key matching --tls-cert-file")
cmd.Flags().BoolVar(&flags.Options.ManageAllNodes, "manage-all-nodes", flags.Options.ManageAllNodes, "All nodes will be watched and managed. It's conflicted with manage-nodes-with-annotation-selector and manage-nodes-with-label-selector.")
cmd.Flags().StringVar(&flags.Options.ManageNodesWithAnnotationSelector, "manage-nodes-with-annotation-selector", flags.Options.ManageNodesWithAnnotationSelector, "Nodes that match the annotation selector will be watched and managed. It's conflicted with manage-all-nodes.")
cmd.Flags().StringVar(&flags.Options.ManageNodesWithLabelSelector, "manage-nodes-with-label-selector", flags.Options.ManageNodesWithLabelSelector, "Nodes that match the label selector will be watched and managed. It's conflicted with manage-all-nodes.")
cmd.Flags().StringVar(&flags.Options.ManageSingleNode, "manage-single-node", flags.Options.ManageSingleNode, "Node that matches the name will be watched and managed. It's conflicted with manage-nodes-with-annotation-selector, manage-nodes-with-label-selector and manage-all-nodes.")
cmd.Flags().BoolVar(&flags.Options.ManageAllNodes, "manage-all-nodes", flags.Options.ManageAllNodes, "All nodes will be watched and managed. It's conflicted with manage-nodes-with-annotation-selector, manage-nodes-with-label-selector and manage-single-node.")
cmd.Flags().StringVar(&flags.Options.ManageNodesWithAnnotationSelector, "manage-nodes-with-annotation-selector", flags.Options.ManageNodesWithAnnotationSelector, "Nodes that match the annotation selector will be watched and managed. It's conflicted with manage-all-nodes and manage-single-node.")
cmd.Flags().StringVar(&flags.Options.ManageNodesWithLabelSelector, "manage-nodes-with-label-selector", flags.Options.ManageNodesWithLabelSelector, "Nodes that match the label selector will be watched and managed. It's conflicted with manage-all-nodes and manage-single-node.")
cmd.Flags().StringVar(&flags.Options.DisregardStatusWithAnnotationSelector, "disregard-status-with-annotation-selector", flags.Options.DisregardStatusWithAnnotationSelector, "All node/pod status excluding the ones that match the annotation selector will be watched and managed.")
cmd.Flags().StringVar(&flags.Options.DisregardStatusWithLabelSelector, "disregard-status-with-label-selector", flags.Options.DisregardStatusWithLabelSelector, "All node/pod status excluding the ones that match the label selector will be watched and managed.")
cmd.Flags().StringVar(&flags.Kubeconfig, "kubeconfig", flags.Kubeconfig, "Path to the kubeconfig file to use")
Expand Down Expand Up @@ -229,24 +230,20 @@ func runE(ctx context.Context, flags *flagpole) error {
return err
}

if flags.Options.ManageAllNodes {
if flags.Options.ManageNodesWithAnnotationSelector != "" || flags.Options.ManageNodesWithLabelSelector != "" {
logger.Error("manage-all-nodes is conflicted with manage-nodes-with-annotation-selector and manage-nodes-with-label-selector.", nil)
os.Exit(1)
}
switch {
case flags.Options.ManageSingleNode != "":
logger.Info("Watch single node",
"node", flags.Options.ManageSingleNode,
)
case flags.Options.ManageAllNodes:
logger.Info("Watch all nodes")
} else if flags.Options.ManageNodesWithAnnotationSelector != "" || flags.Options.ManageNodesWithLabelSelector != "" {
case flags.Options.ManageNodesWithAnnotationSelector != "" || flags.Options.ManageNodesWithLabelSelector != "":
logger.Info("Watch nodes",
"annotation", flags.Options.ManageNodesWithAnnotationSelector,
"label", flags.Options.ManageNodesWithLabelSelector,
)
}

err = waitForReady(ctx, typedClient)
if err != nil {
return err
}

id, err := controllers.Identity()
if err != nil {
return err
Expand All @@ -261,6 +258,7 @@ func runE(ctx context.Context, flags *flagpole) error {
EnableCNI: flags.Options.EnableCNI,
EnableMetrics: enableMetrics,
EnablePodCache: enableMetrics,
ManageSingleNode: flags.Options.ManageSingleNode,
ManageAllNodes: flags.Options.ManageAllNodes,
ManageNodesWithAnnotationSelector: flags.Options.ManageNodesWithAnnotationSelector,
ManageNodesWithLabelSelector: flags.Options.ManageNodesWithLabelSelector,
Expand All @@ -282,6 +280,11 @@ func runE(ctx context.Context, flags *flagpole) error {
return err
}

err = waitForReady(ctx, typedClient)
if err != nil {
return err
}

serverAddress := flags.Options.ServerAddress
if serverAddress == "" && flags.Options.NodePort != 0 {
serverAddress = "0.0.0.0:" + format.String(flags.Options.NodePort)
Expand Down
62 changes: 50 additions & 12 deletions pkg/kwok/controllers/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ type Config struct {
EnableCNI bool
TypedClient kubernetes.Interface
TypedKwokClient versioned.Interface
ManageSingleNode string
ManageAllNodes bool
ManageNodesWithAnnotationSelector string
ManageNodesWithLabelSelector string
Expand All @@ -132,16 +133,31 @@ type Config struct {
EnablePodCache bool
}

// NewController creates a new fake kubelet controller
func NewController(conf Config) (*Controller, error) {
func (c Config) validate() error {
switch {
case conf.ManageAllNodes:
conf.ManageNodesWithAnnotationSelector = ""
conf.ManageNodesWithLabelSelector = ""
case conf.ManageNodesWithAnnotationSelector != "":
case conf.ManageNodesWithLabelSelector != "":
case c.ManageSingleNode != "":
if c.ManageAllNodes {
return fmt.Errorf("manage-single-node is conflicted with manage-all-nodes")
}
if c.ManageNodesWithAnnotationSelector != "" || c.ManageNodesWithLabelSelector != "" {
return fmt.Errorf("manage-single-node is conflicted with manage-nodes-with-annotation-selector or manage-nodes-with-label-selector")
}
case c.ManageAllNodes:
if c.ManageNodesWithAnnotationSelector != "" || c.ManageNodesWithLabelSelector != "" {
return fmt.Errorf("manage-all-nodes is conflicted with manage-nodes-with-annotation-selector or manage-nodes-with-label-selector")
}
case c.ManageNodesWithAnnotationSelector != "" || c.ManageNodesWithLabelSelector != "":
default:
return nil, fmt.Errorf("no nodes are managed")
return fmt.Errorf("no nodes are managed")
}
return nil
}

// NewController creates a new fake kubelet controller
func NewController(conf Config) (*Controller, error) {
err := conf.validate()
if err != nil {
return nil, err
}

n := &Controller{
Expand Down Expand Up @@ -170,14 +186,34 @@ func (c *Controller) Start(ctx context.Context) error {
onLeaseNodeManageFunc func(nodeName string)
onNodeManagedFunc func(nodeName string)
readOnlyFunc func(nodeName string) bool

manageNodesWithLabelSelector string
manageNodesWithAnnotationSelector string
manageNodesWithFieldSelector string
manageNodeLeasesWithFieldSelector string
managePodsWithFieldSelector string
)

switch {
case conf.ManageSingleNode != "":
managePodsWithFieldSelector = fields.OneTermEqualSelector("spec.nodeName", conf.ManageSingleNode).String()
manageNodesWithFieldSelector = fields.OneTermEqualSelector("metadata.name", conf.ManageSingleNode).String()
manageNodeLeasesWithFieldSelector = fields.OneTermEqualSelector("metadata.name", conf.ManageSingleNode).String()
case conf.ManageAllNodes:
managePodsWithFieldSelector = fields.OneTermNotEqualSelector("spec.nodeName", "").String()
case conf.ManageNodesWithLabelSelector != "" || conf.ManageNodesWithAnnotationSelector != "":
manageNodesWithLabelSelector = conf.ManageNodesWithLabelSelector
manageNodesWithAnnotationSelector = conf.ManageNodesWithAnnotationSelector
managePodsWithFieldSelector = fields.OneTermNotEqualSelector("spec.nodeName", "").String()
}

nodeChan := make(chan informer.Event[*corev1.Node], 1)
nodesCli := conf.TypedClient.CoreV1().Nodes()
nodesInformer := informer.NewInformer[*corev1.Node, *corev1.NodeList](nodesCli)
nodesCache, err := nodesInformer.WatchWithCache(ctx, informer.Option{
LabelSelector: conf.ManageNodesWithLabelSelector,
AnnotationSelector: conf.ManageNodesWithAnnotationSelector,
LabelSelector: manageNodesWithLabelSelector,
AnnotationSelector: manageNodesWithAnnotationSelector,
FieldSelector: manageNodesWithFieldSelector,
}, nodeChan)
if err != nil {
return fmt.Errorf("failed to watch nodes: %w", err)
Expand All @@ -188,7 +224,7 @@ func (c *Controller) Start(ctx context.Context) error {
podsInformer := informer.NewInformer[*corev1.Pod, *corev1.PodList](podsCli)

podWatchOption := informer.Option{
FieldSelector: fields.OneTermNotEqualSelector("spec.nodeName", "").String(),
FieldSelector: managePodsWithFieldSelector,
}

var podsCache informer.Getter[*corev1.Pod]
Expand All @@ -205,7 +241,9 @@ func (c *Controller) Start(ctx context.Context) error {
nodeLeasesChan = make(chan informer.Event[*coordinationv1.Lease], 1)
nodeLeasesCli := conf.TypedClient.CoordinationV1().Leases(corev1.NamespaceNodeLease)
nodeLeasesInformer := informer.NewInformer[*coordinationv1.Lease, *coordinationv1.LeaseList](nodeLeasesCli)
err = nodeLeasesInformer.Watch(ctx, informer.Option{}, nodeLeasesChan)
err = nodeLeasesInformer.Watch(ctx, informer.Option{
FieldSelector: manageNodeLeasesWithFieldSelector,
}, nodeLeasesChan)
if err != nil {
return fmt.Errorf("failed to watch nodes: %w", err)
}
Expand Down
32 changes: 27 additions & 5 deletions site/content/en/docs/generated/apis.md
Original file line number Diff line number Diff line change
Expand Up @@ -1860,14 +1860,32 @@ is the default value for flag &ndash;tls-private-key-file</p>
</tr>
<tr>
<td>
<code>manageSingleNode</code>
<em>
string
</em>
</td>
<td>
<p>ManageSingleNode is the option to manage a single node name.
is the default value for flag &ndash;manage-single-node
Note: when <code>manage-all-nodes</code> is specified as true or
<code>manage-nodes-with-label-selector</code> or <code>manage-nodes-with-annotation-selector</code> is specified,
this is a no-op.</p>
</td>
</tr>
<tr>
<td>
<code>manageAllNodes</code>
<em>
bool
</em>
</td>
<td>
<p>Default option to manage (i.e., maintain heartbeat/liveness of) all Nodes or not.
is the default value for flag &ndash;manage-all-nodes</p>
is the default value for flag &ndash;manage-all-nodes
Note: when <code>manage-single-node</code> is specified as true or
<code>manage-nodes-with-label-selector</code> or <code>manage-nodes-with-annotation-selector</code> is specified,
this is a no-op.</p>
</td>
</tr>
<tr>
Expand All @@ -1879,8 +1897,10 @@ string
</td>
<td>
<p>Default annotations specified on Nodes to demand manage.
Note: when <code>all-node-manage</code> is specified as true, this is a no-op.
is the default value for flag &ndash;manage-nodes-with-annotation-selector</p>
is the default value for flag &ndash;manage-nodes-with-annotation-selector
Note: when <code>all-node-manage</code> is specified as true or
<code>manage-single-node</code> is specified,
this is a no-op.</p>
</td>
</tr>
<tr>
Expand All @@ -1892,8 +1912,10 @@ string
</td>
<td>
<p>Default labels specified on Nodes to demand manage.
Note: when <code>all-node-manage</code> is specified as true, this is a no-op.
is the default value for flag &ndash;manage-nodes-with-label-selector</p>
is the default value for flag &ndash;manage-nodes-with-label-selector
Note: when <code>all-node-manage</code> is specified as true or
<code>manage-single-node</code> is specified,
this is a no-op.</p>
</td>
</tr>
<tr>
Expand Down
7 changes: 4 additions & 3 deletions site/content/en/docs/generated/kwok.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ kwok [flags]
--experimental-enable-cni Experimental support for getting pod ip from CNI, for CNI-related components, Only works with Linux
-h, --help help for kwok
--kubeconfig string Path to the kubeconfig file to use (default "~/.kube/config")
--manage-all-nodes All nodes will be watched and managed. It's conflicted with manage-nodes-with-annotation-selector and manage-nodes-with-label-selector.
--manage-nodes-with-annotation-selector string Nodes that match the annotation selector will be watched and managed. It's conflicted with manage-all-nodes.
--manage-nodes-with-label-selector string Nodes that match the label selector will be watched and managed. It's conflicted with manage-all-nodes.
--manage-all-nodes All nodes will be watched and managed. It's conflicted with manage-nodes-with-annotation-selector, manage-nodes-with-label-selector and manage-single-node.
--manage-nodes-with-annotation-selector string Nodes that match the annotation selector will be watched and managed. It's conflicted with manage-all-nodes and manage-single-node.
--manage-nodes-with-label-selector string Nodes that match the label selector will be watched and managed. It's conflicted with manage-all-nodes and manage-single-node.
--manage-single-node string Node that matches the name will be watched and managed. It's conflicted with manage-nodes-with-annotation-selector, manage-nodes-with-label-selector and manage-all-nodes.
--master string The address of the Kubernetes API server (overrides any value in kubeconfig).
--node-ip string IP of the node
--node-lease-duration-seconds uint Duration of node lease seconds
Expand Down
32 changes: 32 additions & 0 deletions test/kwok-single-node/fake-deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: fake-pod
namespace: default
spec:
replicas: 5
selector:
matchLabels:
app: fake-pod
template:
metadata:
labels:
app: fake-pod
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: type
operator: In
values:
- kwok-controller
tolerations:
- key: "kwok-controller/provider"
operator: "Exists"
effect: "NoSchedule"
containers:
- name: fake-container
image: fake
nodeName: fake-node
21 changes: 21 additions & 0 deletions test/kwok-single-node/fake-node.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
apiVersion: v1
kind: Node
metadata:
annotations:
kwok.x-k8s.io/node: fake
node.alpha.kubernetes.io/ttl: "0"
labels:
beta.kubernetes.io/arch: amd64
beta.kubernetes.io/os: linux
kubernetes.io/arch: amd64
kubernetes.io/hostname: fake-node
kubernetes.io/os: linux
kubernetes.io/role: agent
node-role.kubernetes.io/agent: ""
type: kwok-controller
name: fake-node
spec:
taints:
- effect: NoSchedule
key: kwok-controller/provider
value: fake
Loading