karmada/cmd/service-name-resolution-det.../app/options/generic.go

142 lines
4.5 KiB
Go

/*
Copyright 2024 The Karmada Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package options
import (
"fmt"
"net"
"net/url"
"os"
"strings"
"time"
"github.com/spf13/pflag"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/leaderelection/resourcelock"
componentbaseconfig "k8s.io/component-base/config"
componentbaseoptions "k8s.io/component-base/config/options"
"github.com/karmada-io/karmada/pkg/karmadactl/util/apiclient"
)
// GenericOptions contains some generic options.
type GenericOptions struct {
KarmadaKubeConfig string
KarmadaContext string
KarmadaConfig *rest.Config
MemberClusterConfig *rest.Config
ClusterName string
Hostname string
BindAddress string
HealthzPort int
Detectors []string
LeaderElection componentbaseconfig.LeaderElectionConfiguration
}
// NewGenericOptions return default generic options.
func NewGenericOptions() *GenericOptions {
return &GenericOptions{
LeaderElection: componentbaseconfig.LeaderElectionConfiguration{
LeaderElect: true,
ResourceLock: resourcelock.LeasesResourceLock,
ResourceName: "cluster-problem-detector",
ResourceNamespace: "kube-system",
LeaseDuration: metav1.Duration{Duration: 15 * time.Second},
RetryPeriod: metav1.Duration{Duration: 2 * time.Second},
RenewDeadline: metav1.Duration{Duration: 10 * time.Second},
},
}
}
// AddFlags adds flags of generic options to the specified FlagSet.
func (o *GenericOptions) AddFlags(fs *pflag.FlagSet, allDetectors []string) {
fs.StringVar(&o.KarmadaKubeConfig, "karmada-kubeconfig", o.KarmadaKubeConfig, "Path to karmada control plane kubeconfig file.")
fs.StringVar(&o.KarmadaContext, "karmada-context", "", "Name of the cluster context in karmada control plane kubeconfig file.")
fs.StringVar(&o.ClusterName, "cluster-name", o.ClusterName, "Name of member cluster that the agent serves for.")
fs.StringVar(&o.Hostname, "host-name", o.Hostname, "Name of host that the agent runs on, used as lock holder identity.")
fs.StringVar(&o.BindAddress, "bind-address", "127.0.0.1", "The IP address on which to listen.")
fs.IntVar(&o.HealthzPort, "healthz-port", o.HealthzPort, "The port on which to serve health check.")
fs.StringSliceVar(&o.Detectors, "detectors", []string{"*"}, fmt.Sprintf(
"A list of detectors to enable. '*' enables all on-by-default detectors, 'foo' enables the detector named 'foo', '-foo' disables the detector named 'foo'. All detectors: %s.",
strings.Join(allDetectors, ", "),
))
componentbaseoptions.BindLeaderElectionFlags(&o.LeaderElection, fs)
}
// Complete fills in fields required to have valid data.
func (o *GenericOptions) Complete() error {
if o == nil {
return nil
}
controlPlaneRestConfig, err := apiclient.RestConfig(o.KarmadaContext, o.KarmadaKubeConfig)
if err != nil {
return fmt.Errorf("failed to build kubeconfig of karmada control plane: %v", err)
}
o.KarmadaConfig = controlPlaneRestConfig
memberClusterRestConfig, err := rest.InClusterConfig()
if err != nil {
return fmt.Errorf("failed to build in-cluster config: %v", err)
}
o.MemberClusterConfig = memberClusterRestConfig
hostName, err := os.Hostname()
if err != nil {
return fmt.Errorf("failed to get hostname: %v", err)
}
if len(o.Hostname) == 0 {
o.Hostname = hostName
}
return nil
}
// Validate checks options and return a slice of found errs.
func (o *GenericOptions) Validate() field.ErrorList {
errs := field.ErrorList{}
if err := validateAPIServerAddr(o.MemberClusterConfig.Host); err != nil {
errs = append(errs, field.InternalError(field.NewPath("InClusterConfig"), err))
}
return errs
}
func validateAPIServerAddr(addr string) error {
server, err := url.Parse(addr)
if err != nil {
return err
}
host, _, err := net.SplitHostPort(server.Host)
if err != nil {
return err
}
// The host must be an IP rather than a domain name.
if net.ParseIP(host) == nil {
return fmt.Errorf("server address of member cluster kubeconfig must be an IP")
}
return nil
}