mirror of
https://github.com/kubernetes-sigs/node-feature-discovery.git
synced 2025-04-16 09:16:31 +00:00
Merge pull request #326 from marquiz/devel/prune
nfd-master: implement --prune flag
This commit is contained in:
commit
9df73b8ace
6 changed files with 112 additions and 15 deletions
|
@ -50,18 +50,20 @@ Command line flags of nfd-master:
|
|||
```
|
||||
$ docker run --rm <NFD_CONTAINER_IMAGE> nfd-master --help
|
||||
...
|
||||
nfd-master.
|
||||
|
||||
Usage:
|
||||
nfd-master [--no-publish] [--label-whitelist=<pattern>] [--port=<port>]
|
||||
nfd-master [--prune] [--no-publish] [--label-whitelist=<pattern>] [--port=<port>]
|
||||
[--ca-file=<path>] [--cert-file=<path>] [--key-file=<path>]
|
||||
[--verify-node-name] [--extra-label-ns=<list>] [--resource-labels=<list>]
|
||||
[--kubeconfig=<path>]
|
||||
nfd-master -h | --help
|
||||
nfd-master --version
|
||||
|
||||
Options:
|
||||
-h --help Show this screen.
|
||||
--version Output version and exit.
|
||||
--prune Prune all NFD related attributes from all nodes
|
||||
of the cluster and exit.
|
||||
--kubeconfig=<path> Kubeconfig to use [Default: ]
|
||||
--port=<port> Port on which to listen for connections.
|
||||
[Default: 8080]
|
||||
--ca-file=<path> Root certificate for verifying connections
|
||||
|
|
|
@ -63,15 +63,20 @@ func argsParse(argv []string) (master.Args, error) {
|
|||
usage := fmt.Sprintf(`%s.
|
||||
|
||||
Usage:
|
||||
%s [--no-publish] [--label-whitelist=<pattern>] [--port=<port>]
|
||||
%s [--prune] [--no-publish] [--label-whitelist=<pattern>] [--port=<port>]
|
||||
[--ca-file=<path>] [--cert-file=<path>] [--key-file=<path>]
|
||||
[--verify-node-name] [--extra-label-ns=<list>] [--resource-labels=<list>]
|
||||
[--kubeconfig=<path>]
|
||||
%s -h | --help
|
||||
%s --version
|
||||
|
||||
Options:
|
||||
-h --help Show this screen.
|
||||
--version Output version and exit.
|
||||
--prune Prune all NFD related attributes from all nodes
|
||||
of the cluster and exit.
|
||||
--kubeconfig=<path> Kubeconfig to use [Default: ]
|
||||
of the cluster and exit.
|
||||
--port=<port> Port on which to listen for connections.
|
||||
[Default: 8080]
|
||||
--ca-file=<path> Root certificate for verifying connections
|
||||
|
@ -119,6 +124,8 @@ func argsParse(argv []string) (master.Args, error) {
|
|||
args.VerifyNodeName = arguments["--verify-node-name"].(bool)
|
||||
args.ExtraLabelNs = strings.Split(arguments["--extra-label-ns"].(string), ",")
|
||||
args.ResourceLabels = strings.Split(arguments["--resource-labels"].(string), ",")
|
||||
args.Prune = arguments["--prune"].(bool)
|
||||
args.Kubeconfig = arguments["--kubeconfig"].(string)
|
||||
|
||||
return args, nil
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@ type APIHelpers interface {
|
|||
// GetNode returns the Kubernetes node on which this container is running.
|
||||
GetNode(*k8sclient.Clientset, string) (*api.Node, error)
|
||||
|
||||
// GetNodes returns all the nodes in the cluster
|
||||
GetNodes(*k8sclient.Clientset) (*api.NodeList, error)
|
||||
|
||||
// UpdateNode updates the node via the API server using a client.
|
||||
UpdateNode(*k8sclient.Clientset, *api.Node) error
|
||||
|
||||
|
|
|
@ -24,18 +24,28 @@ import (
|
|||
"k8s.io/apimachinery/pkg/types"
|
||||
k8sclient "k8s.io/client-go/kubernetes"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
// Implements APIHelpers
|
||||
type K8sHelpers struct {
|
||||
Kubeconfig string
|
||||
}
|
||||
|
||||
func (h K8sHelpers) GetClient() (*k8sclient.Clientset, error) {
|
||||
// Set up an in-cluster K8S client.
|
||||
config, err := restclient.InClusterConfig()
|
||||
var config *restclient.Config
|
||||
var err error
|
||||
|
||||
if h.Kubeconfig == "" {
|
||||
config, err = restclient.InClusterConfig()
|
||||
} else {
|
||||
config, err = clientcmd.BuildConfigFromFlags("", h.Kubeconfig)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
clientset, err := k8sclient.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -53,6 +63,10 @@ func (h K8sHelpers) GetNode(cli *k8sclient.Clientset, nodeName string) (*api.Nod
|
|||
return node, nil
|
||||
}
|
||||
|
||||
func (h K8sHelpers) GetNodes(cli *k8sclient.Clientset) (*api.NodeList, error) {
|
||||
return cli.CoreV1().Nodes().List(meta_v1.ListOptions{})
|
||||
}
|
||||
|
||||
func (h K8sHelpers) UpdateNode(c *k8sclient.Clientset, n *api.Node) error {
|
||||
// Send the updated node to the apiserver.
|
||||
_, err := c.CoreV1().Nodes().Update(n)
|
||||
|
|
|
@ -62,6 +62,29 @@ func (_m *MockAPIHelpers) GetNode(_a0 *kubernetes.Clientset, _a1 string) (*v1.No
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// GetNodes provides a mock function with given fields: _a0
|
||||
func (_m *MockAPIHelpers) GetNodes(_a0 *kubernetes.Clientset) (*v1.NodeList, error) {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
var r0 *v1.NodeList
|
||||
if rf, ok := ret.Get(0).(func(*kubernetes.Clientset) *v1.NodeList); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1.NodeList)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(*kubernetes.Clientset) error); ok {
|
||||
r1 = rf(_a0)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// PatchStatus provides a mock function with given fields: _a0, _a1, _a2
|
||||
func (_m *MockAPIHelpers) PatchStatus(_a0 *kubernetes.Clientset, _a1 string, _a2 interface{}) error {
|
||||
ret := _m.Called(_a0, _a1, _a2)
|
||||
|
|
|
@ -70,9 +70,11 @@ type Args struct {
|
|||
CertFile string
|
||||
ExtraLabelNs []string
|
||||
KeyFile string
|
||||
Kubeconfig string
|
||||
LabelWhiteList *regexp.Regexp
|
||||
NoPublish bool
|
||||
Port int
|
||||
Prune bool
|
||||
VerifyNodeName bool
|
||||
ResourceLabels []string
|
||||
}
|
||||
|
@ -87,6 +89,7 @@ type nfdMaster struct {
|
|||
args Args
|
||||
server *grpc.Server
|
||||
ready chan bool
|
||||
apihelper apihelper.APIHelpers
|
||||
}
|
||||
|
||||
// statusOp is a json marshaling helper used for patching node status
|
||||
|
@ -121,6 +124,9 @@ func NewNfdMaster(args Args) (NfdMaster, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// Initialize Kubernetes API helpers
|
||||
nfd.apihelper = apihelper.K8sHelpers{Kubeconfig: args.Kubeconfig}
|
||||
|
||||
return nfd, nil
|
||||
}
|
||||
|
||||
|
@ -130,11 +136,12 @@ func (m *nfdMaster) Run() error {
|
|||
stdoutLogger.Printf("Node Feature Discovery Master %s", version.Get())
|
||||
stdoutLogger.Printf("NodeName: '%s'", nodeName)
|
||||
|
||||
// Initialize Kubernetes API helpers
|
||||
helper := apihelper.APIHelpers(apihelper.K8sHelpers{})
|
||||
if m.args.Prune {
|
||||
return m.prune()
|
||||
}
|
||||
|
||||
if !m.args.NoPublish {
|
||||
err := updateMasterNode(helper)
|
||||
err := updateMasterNode(m.apihelper)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update master node: %v", err)
|
||||
}
|
||||
|
@ -176,7 +183,7 @@ func (m *nfdMaster) Run() error {
|
|||
serverOpts = append(serverOpts, grpc.Creds(credentials.NewTLS(tlsConfig)))
|
||||
}
|
||||
m.server = grpc.NewServer(serverOpts...)
|
||||
pb.RegisterLabelerServer(m.server, &labelerServer{args: m.args, apiHelper: helper})
|
||||
pb.RegisterLabelerServer(m.server, &labelerServer{args: m.args, apiHelper: m.apihelper})
|
||||
stdoutLogger.Printf("gRPC server serving on port: %d", m.args.Port)
|
||||
return m.server.Serve(lis)
|
||||
}
|
||||
|
@ -201,6 +208,46 @@ func (m *nfdMaster) WaitForReady(timeout time.Duration) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// Prune erases all NFD related properties from the node objects of the cluster.
|
||||
func (m *nfdMaster) prune() error {
|
||||
cli, err := m.apihelper.GetClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodes, err := m.apihelper.GetNodes(cli)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, node := range nodes.Items {
|
||||
stdoutLogger.Printf("pruning node %q...", node.Name)
|
||||
|
||||
// Prune labels and extended resources
|
||||
err := updateNodeFeatures(m.apihelper, node.Name, Labels{}, Annotations{}, ExtendedResources{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to prune labels from node %q: %v", node.Name, err)
|
||||
}
|
||||
|
||||
// Prune annotations
|
||||
node, err := m.apihelper.GetNode(cli, node.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for a := range node.Annotations {
|
||||
if strings.HasPrefix(a, AnnotationNs) {
|
||||
delete(node.Annotations, a)
|
||||
}
|
||||
}
|
||||
err = m.apihelper.UpdateNode(cli, node)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to prune annotations from node %q: %v", node.Name, err)
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Advertise NFD master information
|
||||
func updateMasterNode(helper apihelper.APIHelpers) error {
|
||||
cli, err := helper.GetClient()
|
||||
|
@ -332,8 +379,9 @@ func (s *labelerServer) SetLabels(c context.Context, r *pb.SetLabelsRequest) (*p
|
|||
return &pb.SetLabelsReply{}, nil
|
||||
}
|
||||
|
||||
// advertiseFeatureLabels advertises the feature labels to a Kubernetes node
|
||||
// via the API server.
|
||||
// updateNodeFeatures ensures the Kubernetes node object is up to date,
|
||||
// creating new labels and extended resources where necessary and removing
|
||||
// outdated ones. Also updates the corresponding annotations.
|
||||
func updateNodeFeatures(helper apihelper.APIHelpers, nodeName string, labels Labels, annotations Annotations, extendedResources ExtendedResources) error {
|
||||
cli, err := helper.GetClient()
|
||||
if err != nil {
|
||||
|
|
Loading…
Add table
Reference in a new issue