diff --git a/apps/devops/entity/k8s/configmap.go b/apps/devops/entity/k8s/configmap.go deleted file mode 100644 index 9923dae..0000000 --- a/apps/devops/entity/k8s/configmap.go +++ /dev/null @@ -1,6 +0,0 @@ -package k8s - -type ConfigMapData struct { - Namespace string `json:"namespace" binding:"required"` - Name string `json:"name" binding:"required"` -} diff --git a/apps/devops/entity/k8s/daemonset.go b/apps/devops/entity/k8s/daemonset.go deleted file mode 100644 index 29c9489..0000000 --- a/apps/devops/entity/k8s/daemonset.go +++ /dev/null @@ -1,6 +0,0 @@ -package k8s - -type DaemonSetData struct { - Namespace string `json:"namespace" binding:"required"` - Name string `json:"name" binding:"required"` -} diff --git a/apps/devops/entity/k8s/deployment.go b/apps/devops/entity/k8s/deployment.go deleted file mode 100644 index 8f6871a..0000000 --- a/apps/devops/entity/k8s/deployment.go +++ /dev/null @@ -1,30 +0,0 @@ -package k8s - -type RemoveDeploymentData struct { - Namespace string `json:"namespace" binding:"required"` - DeploymentName string `json:"deploymentName" binding:"required"` -} - -type ScaleDeployment struct { - ScaleNumber *int32 `json:"scaleNumber" binding:"required"` - Namespace string `json:"namespace" binding:"required"` - DeploymentName string `json:"deploymentName" binding:"required"` -} - -type RestartDeployment struct { - Namespace string `json:"namespace" binding:"required"` - DeploymentName string `json:"deploymentName" binding:"required"` -} - -type RemoveDeploymentToServiceData struct { - IsDeleteService bool `json:"isDeleteService" binding:"required"` - ServiceName string `json:"serviceName" binding:"required"` - Namespace string `json:"namespace" binding:"required"` - DeploymentName string `json:"deploymentName" binding:"required"` -} - -type RollbackDeployment struct { - Namespace string `json:"namespace" binding:"required"` - DeploymentName string `json:"deploymentName" binding:"required"` - ReVersion *int64 `json:"reVersion" binding:"required"` -} diff --git a/apps/devops/entity/k8s/job.go b/apps/devops/entity/k8s/job.go deleted file mode 100644 index 65088bc..0000000 --- a/apps/devops/entity/k8s/job.go +++ /dev/null @@ -1,13 +0,0 @@ -package k8s - -type JobData struct { - Namespace string `json:"namespace" binding:"required"` - Name string `json:"name" binding:"required"` -} - -type ScaleJob struct { - Namespace string `json:"namespace" binding:"required"` - Name string `json:"name" binding:"required"` - // Job并行运行的Pod数量 - Number *int32 `json:"number" binding:"required"` -} diff --git a/apps/devops/entity/k8s/k8s_cluster.go b/apps/devops/entity/k8s/k8s_cluster.go deleted file mode 100644 index 93de8ac..0000000 --- a/apps/devops/entity/k8s/k8s_cluster.go +++ /dev/null @@ -1,34 +0,0 @@ -package k8s - -type K8SCluster struct { - ClusterName string `json:"clusterName" gorm:"comment:集群名称" form:"clusterName" binding:"required"` - KubeConfig string `json:"kubeConfig" gorm:"comment:集群凭证;type:varchar(12800)" binding:"required"` - ClusterVersion string `json:"clusterVersion" gorm:"comment:集群版本"` - NodeNumber int `json:"nodeNumber" gorm:"comment:节点数"` -} - -type PaginationQ struct { - Size int `form:"size" json:"size"` - Page int `form:"page" json:"page"` - Total int64 `json:"total"` - Keyword string `form:"keyword" json:"keyword"` -} - -type ClusterIds struct { - Data interface{} `json:"clusterIds"` -} - -type ClusterNodesStatus struct { - NodeCount int `json:"node_count"` - Ready int `json:"ready"` - UnReady int `json:"unready"` - Namespace int `json:"namespace"` - Deployment int `json:"deployment"` - Pod int `json:"pod"` - CpuUsage float64 `json:"cpu_usage" desc:"cpu使用率"` - CpuCore float64 `json:"cpu_core"` - CpuCapacityCore float64 `json:"cpu_capacity_core"` - MemoryUsage float64 `json:"memory_usage" desc:"内存使用率"` - MemoryUsed float64 `json:"memory_used"` - MemoryTotal float64 `json:"memory_total"` -} diff --git a/apps/devops/entity/k8s/node.go b/apps/devops/entity/k8s/node.go deleted file mode 100644 index 4323fb7..0000000 --- a/apps/devops/entity/k8s/node.go +++ /dev/null @@ -1,112 +0,0 @@ -package k8s - -import "time" - -// ListMeta describes list of objects, i.e. holds information about pagination options set for the list. -type ListMeta struct { - // Total number of items on the list. Used for pagination. - TotalItems int `json:"totalItems"` -} - -// ObjectMeta is metadata about an instance of a resource. -type ObjectMeta struct { - // Name is unique within a namespace. Name is primarily intended for creation - // idempotence and configuration definition. - Name string `json:"name,omitempty"` - - // Namespace defines the space within which name must be unique. An empty namespace is - // equivalent to the "default" namespace, but "default" is the canonical representation. - // Not all objects are required to be scoped to a namespace - the value of this field for - // those objects will be empty. - Namespace string `json:"namespace,omitempty"` - - // Labels are key value pairs that may be used to scope and select individual resources. - // Label keys are of the form: - // label-key ::= prefixed-name | name - // prefixed-name ::= prefix '/' name - // prefix ::= DNS_SUBDOMAIN - // name ::= DNS_LABEL - // The prefix is optional. If the prefix is not specified, the key is assumed to be private - // to the user. Other system components that wish to use labels must specify a prefix. - Labels map[string]string `json:"labels,omitempty"` - - // Annotations are unstructured key value data stored with a resource that may be set by - // external tooling. They are not queryable and should be preserved when modifying - // objects. Annotation keys have the same formatting restrictions as Label keys. See the - // comments on Labels for details. - Annotations map[string]string `json:"annotations,omitempty"` - - // CreationTimestamp is a timestamp representing the server time when this object was - // created. It is not guaranteed to be set in happens-before order across separate operations. - // Clients may not set this value. It is represented in RFC3339 form and is in UTC. - CreationTimestamp Time `json:"creationTimestamp,omitempty"` -} - -// TypeMeta describes an individual object in an API response or request with strings representing -// the type of the object. -type TypeMeta struct { - // Kind is a string value representing the REST resource this object represents. - // Servers may infer this from the endpoint the client submits requests to. - // In smalllettercase. - // More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds - Kind ResourceKind `json:"kind,omitempty"` -} - -// NodeAllocatedResources describes node allocated resources. -type NodeAllocatedResources struct { - // CPURequests is number of allocated milicores. - CPURequests int64 `json:"cpuRequests"` - - // CPURequestsFraction is a fraction of CPU, that is allocated. - CPURequestsFraction float64 `json:"cpuRequestsFraction"` - - // CPULimits is defined CPU limit. - CPULimits int64 `json:"cpuLimits"` - - // CPULimitsFraction is a fraction of defined CPU limit, can be over 100%, i.e. - // overcommitted. - CPULimitsFraction float64 `json:"cpuLimitsFraction"` - - // CPUCapacity is specified node CPU capacity in milicores. - CPUCapacity int64 `json:"cpuCapacity"` - - // MemoryRequests is a fraction of memory, that is allocated. - MemoryRequests int64 `json:"memoryRequests"` - - // MemoryRequestsFraction is a fraction of memory, that is allocated. - MemoryRequestsFraction float64 `json:"memoryRequestsFraction"` - - // MemoryLimits is defined memory limit. - MemoryLimits int64 `json:"memoryLimits"` - - // MemoryLimitsFraction is a fraction of defined memory limit, can be over 100%, i.e. - // overcommitted. - MemoryLimitsFraction float64 `json:"memoryLimitsFraction"` - - // MemoryCapacity is specified node memory capacity in bytes. - MemoryCapacity int64 `json:"memoryCapacity"` - - // AllocatedPods in number of currently allocated pods on the node. - AllocatedPods int `json:"allocatedPods"` - - // PodCapacity is maximum number of pods, that can be allocated on the node. - PodCapacity int64 `json:"podCapacity"` - - // PodFraction is a fraction of pods, that can be allocated on given node. - PodFraction float64 `json:"podFraction"` -} - -type Time struct { - time.Time `protobuf:"-"` -} - -// ResourceKind is an unique name for each resource. It can used for API discovery and generic -// code that does things based on the kind. For example, there may be a generic "deleter" -// that based on resource kind, name and namespace deletes it. -type ResourceKind string - -type Unschedulable bool - -type NodeIP string - -type UID string diff --git a/apps/devops/entity/k8s/pod.go b/apps/devops/entity/k8s/pod.go deleted file mode 100644 index bc9d9a4..0000000 --- a/apps/devops/entity/k8s/pod.go +++ /dev/null @@ -1,6 +0,0 @@ -package k8s - -type RemovePodsData struct { - Namespace string `json:"namespace" binding:"required"` - PodName string `json:"podName" binding:"required"` -} diff --git a/apps/devops/entity/k8s/secrets.go b/apps/devops/entity/k8s/secrets.go deleted file mode 100644 index c312d2c..0000000 --- a/apps/devops/entity/k8s/secrets.go +++ /dev/null @@ -1,6 +0,0 @@ -package k8s - -type SecretsData struct { - Namespace string `json:"namespace" binding:"required"` - Name string `json:"name" binding:"required"` -} diff --git a/apps/devops/entity/k8s/service.go b/apps/devops/entity/k8s/service.go deleted file mode 100644 index 4c4b2c7..0000000 --- a/apps/devops/entity/k8s/service.go +++ /dev/null @@ -1,6 +0,0 @@ -package k8s - -type ServiceData struct { - Namespace string `json:"namespace" binding:"required"` - Name string `json:"name" binding:"required"` -} diff --git a/apps/devops/entity/k8s/statefulset.go b/apps/devops/entity/k8s/statefulset.go deleted file mode 100644 index 5d5f177..0000000 --- a/apps/devops/entity/k8s/statefulset.go +++ /dev/null @@ -1,12 +0,0 @@ -package k8s - -type StatefulSetData struct { - Namespace string `json:"namespace" binding:"required"` - Name string `json:"name" binding:"required"` -} - -type ScaleStatefulSet struct { - ScaleNumber *int32 `json:"scaleNumber" binding:"required"` - Namespace string `json:"namespace" binding:"required"` - Name string `json:"name" binding:"required"` -} diff --git a/apps/devops/entity/k8s/types.go b/apps/devops/entity/k8s/types.go deleted file mode 100644 index 804a2ff..0000000 --- a/apps/devops/entity/k8s/types.go +++ /dev/null @@ -1,66 +0,0 @@ -package k8s - -import ( - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/labels" -) - -// NewObjectMeta returns internal endpoint name for the given service properties, e.g., -// NewObjectMeta creates a new instance of ObjectMeta struct based on K8s object meta. -func NewObjectMeta(k8SObjectMeta metaV1.ObjectMeta) ObjectMeta { - return ObjectMeta{ - Name: k8SObjectMeta.Name, - Namespace: k8SObjectMeta.Namespace, - Labels: k8SObjectMeta.Labels, - CreationTimestamp: Time(k8SObjectMeta.CreationTimestamp), - Annotations: k8SObjectMeta.Annotations, - } -} - -// NewTypeMeta creates new type mete for the resource kind. -func NewTypeMeta(kind ResourceKind) TypeMeta { - return TypeMeta{ - Kind: kind, - } -} - -// ListEverything is a list options used to list all resources without any filtering. -var ListEverything = metaV1.ListOptions{ - LabelSelector: labels.Everything().String(), - FieldSelector: fields.Everything().String(), -} - -// List of all resource kinds supported by the UI. -const ( - ResourceKindConfigMap = "configmap" - ResourceKindDaemonSet = "daemonset" - ResourceKindDeployment = "deployment" - ResourceKindEvent = "event" - ResourceKindHorizontalPodAutoscaler = "horizontalpodautoscaler" - ResourceKindIngress = "ingress" - ResourceKindServiceAccount = "serviceaccount" - ResourceKindJob = "job" - ResourceKindCronJob = "cronjob" - ResourceKindLimitRange = "limitrange" - ResourceKindNamespace = "namespace" - ResourceKindNode = "node" - ResourceKindPersistentVolumeClaim = "persistentvolumeclaim" - ResourceKindPersistentVolume = "persistentvolume" - ResourceKindCustomResourceDefinition = "customresourcedefinition" - ResourceKindPod = "pod" - ResourceKindReplicaSet = "replicaset" - ResourceKindReplicationController = "replicationcontroller" - ResourceKindResourceQuota = "resourcequota" - ResourceKindSecret = "secret" - ResourceKindService = "service" - ResourceKindStatefulSet = "statefulset" - ResourceKindStorageClass = "storageclass" - ResourceKindClusterRole = "clusterrole" - ResourceKindClusterRoleBinding = "clusterrolebinding" - ResourceKindRole = "role" - ResourceKindRoleBinding = "rolebinding" - ResourceKindPlugin = "plugin" - ResourceKindEndpoint = "endpoint" - ResourceKindNetworkPolicy = "networkpolicy" -) diff --git a/apps/devops/services/k8s/Init/container.go b/apps/devops/services/k8s/Init/container.go deleted file mode 100644 index 7d09857..0000000 --- a/apps/devops/services/k8s/Init/container.go +++ /dev/null @@ -1,84 +0,0 @@ -package Init - -import ( - "context" - "errors" - "fmt" - "io" - "io/ioutil" - "k8s.io/client-go/dynamic" - "os" - "pandax/base/global" - "path/filepath" - - "go.uber.org/zap" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" -) - -// GetK8sClient 获取k8s Client -func GetK8sClient(ctx context.Context, kubeConfig string) (*kubernetes.Clientset, error) { - var config *rest.Config - var err error - if kubeConfig != "" { - clientConfig := GetClientConfig(kubeConfig, nil) - config, err = clientConfig.ClientConfig() - if err != nil { - return nil, errors.New("KubeConfig内容错误") - } - } else { - config, err = rest.InClusterConfig() - if err != nil { - return nil, errors.New("KubeConfig内容错误") - } - } - - //config, err := clientcmd.RESTConfigFromKubeConfig([]byte(k8sConf)) - // skips the validity check for the server's certificate. This will make your HTTPS connections insecure. - // config.TLSClientConfig.Insecure = true - clientSet, err := kubernetes.NewForConfig(config) - if err != nil { - global.Log.Error("创建Client失败", zap.Any("err", err)) - return nil, errors.New("创建Client失败!") - } - _, err = dynamic.NewForConfig(config) - if err != nil { - return nil, fmt.Errorf("kubernetes dynamic client create error:%s", err.Error()) - } - return clientSet, nil -} - -func GetClientConfig(kubeConfig string, reader io.Reader) clientcmd.ClientConfig { - loadingRules := GetLoadingRules(kubeConfig) - overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults} - return clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, overrides, reader) -} - -func GetLoadingRules(kubeConfig string) *clientcmd.ClientConfigLoadingRules { - loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() - loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig - if kubeConfig != "" { - loadingRules.ExplicitPath = kubeConfig - } - - var otherFiles []string - homeDir, err := os.UserHomeDir() - if err == nil { - otherFiles = append(otherFiles, filepath.Join(homeDir, ".kube", "k3s.yaml")) - } - otherFiles = append(otherFiles, "/etc/rancher/k3s/k3s.yaml") - loadingRules.Precedence = append(loadingRules.Precedence, canRead(otherFiles)...) - - return loadingRules -} - -func canRead(files []string) (result []string) { - for _, f := range files { - _, err := ioutil.ReadFile(f) - if err == nil { - result = append(result, f) - } - } - return -} diff --git a/apps/devops/services/k8s/cluster/client_test.go b/apps/devops/services/k8s/cluster/client_test.go deleted file mode 100644 index 7f29015..0000000 --- a/apps/devops/services/k8s/cluster/client_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package cluster - -import ( - "context" - "fmt" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/json" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/clientcmd" - clientcmdapi "k8s.io/client-go/tools/clientcmd/api" - "log" - "testing" -) - -func TestGetNodeList(t *testing.T) { - rules := clientcmd.NewDefaultClientConfigLoadingRules() - overrides := &clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{InsecureSkipTLSVerify: true}} - config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(rules, overrides).ClientConfig() - if err != nil { - log.Fatalf("Couldn't get Kubernetes default config: %s", err) - } - - client, err := kubernetes.NewForConfig(config) - if err != nil { - log.Fatalln(err) - } - - nodes, err := client.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{}) - for _, c := range nodes.Items { - j, _ := json.Marshal(c) - fmt.Println(string(j)) - } -} diff --git a/apps/devops/services/k8s/cluster/cluster.go b/apps/devops/services/k8s/cluster/cluster.go deleted file mode 100644 index 03ea830..0000000 --- a/apps/devops/services/k8s/cluster/cluster.go +++ /dev/null @@ -1,145 +0,0 @@ -package cluster - -import ( - "context" - "github.com/prometheus/common/expfmt" - "go.uber.org/zap" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - "pandax/base/global" - "pandax/base/utils" - "strings" -) - -func GetClusterVersion(c *kubernetes.Clientset) (string, error) { - /* - 获取k8s 集群版本 - */ - version, err := c.ServerVersion() - - if err != nil { - global.Log.Error("get version from cluster failed", zap.Any("err: ", err)) - return "", err - } - - return version.String(), nil -} - -func GetClusterNodesNumber(c *kubernetes.Clientset) (int, error) { - /* - 获取k8s node节点数量 - */ - nodes, err := c.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{}) - if err != nil { - return 0, err - } - return len(nodes.Items), nil -} - -func GetClusterNodesRunningStatus(c *kubernetes.Clientset, m *k8s.ClusterNodesStatus) *k8s.ClusterNodesStatus { - /* - 统计k8s 集群node节点 就绪数量 - */ - nodes, err := c.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{}) - if err != nil { - global.Log.Error("get nodes err", zap.Any("err: ", err)) - } - - var ready int = 0 - var unready int = 0 - for _, node := range nodes.Items { - listNode, _ := c.CoreV1().Nodes().Get(context.TODO(), node.ObjectMeta.Name, metav1.GetOptions{}) - - if len(listNode.Status.Conditions) >= 0 { - if string(listNode.Status.Conditions[len(listNode.Status.Conditions)-1].Status) == "True" { - ready += 1 - } else { - unready += 1 - } - } else { - global.Log.Error("get nodes ready err") - return &k8s.ClusterNodesStatus{} - } - } - m.Ready = ready - m.UnReady = unready - return m -} - -func GetClusterInfo(c *kubernetes.Clientset) *k8s.ClusterNodesStatus { - /* - 获取集群信息 - */ - var node k8s.ClusterNodesStatus - //nodeNumber, _ := GetClusterNodesNumber(c) - //node.Total = nodeNumber - - // eg: node节点不健康 - _ = GetClusterNodesRunningStatus(c, &node) - - //namespace, deployment, pod := GetNodeResource(c) - //node.Namespace = namespace - //node.Deployment = deployment - //node.Pod = pod - - data, _ := c.RESTClient().Get().AbsPath("/api/v1/namespaces/kube-system/services/tke-kube-state-metrics:http-metrics/proxy/metrics").DoRaw(context.TODO()) - - var parser expfmt.TextParser - mf, err := parser.TextToMetricFamilies(strings.NewReader(string(data))) - if err != nil { - global.Log.Error("解析metrics错误", zap.Any("err:", err)) - return nil - } - - var ( - // cpuUsage - kubePodContainerResourceRequestsCpuCores float64 = 0 - kubeNodeStatusCapacityCpuCores float64 = 0 - // memoryUsage - kubePodContainerResourceRequestsMemoryBytes float64 = 0 - kubeNodeStatusAllocatableMemoryBytes float64 = 0 - ) - - for metricIndex, metricValue := range mf { - // sum(kube_pod_container_resource_requests_cpu_cores{node!~"master-.*"})/sum(kube_node_status_capacity_cpu_cores{node!~"master-.*"})*100 - if metricIndex == "kube_pod_container_resource_requests_cpu_cores" { - for _, metric := range metricValue.GetMetric() { - kubePodContainerResourceRequestsCpuCores += *metric.Gauge.Value - } - } - if metricIndex == "kube_node_status_capacity_cpu_cores" { - for _, metric := range metricValue.GetMetric() { - kubeNodeStatusCapacityCpuCores += *metric.Gauge.Value - } - } - // sum(kube_pod_container_resource_requests_memory_bytes{node!~"master-.*"})/sum(kube_node_status_allocatable_memory_bytes{node!~"master-.*"})*100 - if metricIndex == "kube_pod_container_resource_requests_memory_bytes" { - for _, metric := range metricValue.GetMetric() { - kubePodContainerResourceRequestsMemoryBytes += *metric.Gauge.Value - } - } - if metricIndex == "kube_node_status_allocatable_memory_bytes" { - for _, metric := range metricValue.GetMetric() { - kubeNodeStatusAllocatableMemoryBytes += *metric.Gauge.Value - } - } - - // 计算Node节点数量 - if metricIndex == "kube_node_info" { - node.NodeCount = len(metricValue.Metric) - } - - } - - node.CpuCore = utils.ParseFloat2F(kubePodContainerResourceRequestsCpuCores) - node.CpuUsage = utils.ParseFloat2F(kubePodContainerResourceRequestsCpuCores / kubeNodeStatusCapacityCpuCores * 100) - node.CpuCapacityCore = utils.ParseFloat2F(kubeNodeStatusCapacityCpuCores) - - node.MemoryUsed = utils.ParseFloat2F(kubePodContainerResourceRequestsMemoryBytes / 1024 / 1024 / 1024) - node.MemoryUsage = utils.ParseFloat2F(kubePodContainerResourceRequestsMemoryBytes / kubeNodeStatusAllocatableMemoryBytes * 100) - node.MemoryTotal = utils.ParseFloat2F(kubeNodeStatusAllocatableMemoryBytes / 1024 / 1024 / 1024) - - return &node - -} diff --git a/apps/devops/services/k8s/common/common.go b/apps/devops/services/k8s/common/common.go deleted file mode 100644 index f118657..0000000 --- a/apps/devops/services/k8s/common/common.go +++ /dev/null @@ -1,19 +0,0 @@ -package common - -import v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - -// Condition represents a single condition of a pod or node. -type Condition struct { - // Type of a condition. - Type string `json:"type"` - // Status of a condition. - Status v1.ConditionStatus `json:"status"` - // Last probe time of a condition. - LastProbeTime v1.Time `json:"lastProbeTime"` - // Last transition time of a condition. - LastTransitionTime v1.Time `json:"lastTransitionTime"` - // Reason of a condition. - Reason string `json:"reason"` - // Message of a condition. - Message string `json:"message"` -} diff --git a/apps/devops/services/k8s/common/endpoint.go b/apps/devops/services/k8s/common/endpoint.go deleted file mode 100644 index 9ed1682..0000000 --- a/apps/devops/services/k8s/common/endpoint.go +++ /dev/null @@ -1,66 +0,0 @@ -package common - -import ( - "bytes" - api "k8s.io/api/core/v1" -) - -// Endpoint describes an endpoint that is host and a list of available ports for that host. -type Endpoint struct { - // Hostname, either as a domain name or IP address. - Host string `json:"host"` - - // List of ports opened for this endpoint on the hostname. - Ports []ServicePort `json:"ports"` -} - -// GetExternalEndpoints returns endpoints that are externally reachable for a service. -func GetExternalEndpoints(service *api.Service) []Endpoint { - externalEndpoints := make([]Endpoint, 0) - if service.Spec.Type == api.ServiceTypeLoadBalancer { - for _, ingress := range service.Status.LoadBalancer.Ingress { - externalEndpoints = append(externalEndpoints, getExternalEndpoint(ingress, service.Spec.Ports)) - } - } - - for _, ip := range service.Spec.ExternalIPs { - externalEndpoints = append(externalEndpoints, Endpoint{ - Host: ip, - Ports: GetServicePorts(service.Spec.Ports), - }) - } - - return externalEndpoints -} - -// GetInternalEndpoint returns internal endpoint name for the given service properties, e.g., -// "my-service.namespace 80/TCP" or "my-service 53/TCP,53/UDP". -func GetInternalEndpoint(serviceName, namespace string, ports []api.ServicePort) Endpoint { - name := serviceName - - if namespace != api.NamespaceDefault && len(namespace) > 0 && len(serviceName) > 0 { - bufferName := bytes.NewBufferString(name) - bufferName.WriteString(".") - bufferName.WriteString(namespace) - name = bufferName.String() - } - - return Endpoint{ - Host: name, - Ports: GetServicePorts(ports), - } -} - -// Returns external endpoint name for the given service properties. -func getExternalEndpoint(ingress api.LoadBalancerIngress, ports []api.ServicePort) Endpoint { - var host string - if ingress.Hostname != "" { - host = ingress.Hostname - } else { - host = ingress.IP - } - return Endpoint{ - Host: host, - Ports: GetServicePorts(ports), - } -} diff --git a/apps/devops/services/k8s/common/event.go b/apps/devops/services/k8s/common/event.go deleted file mode 100644 index b040a10..0000000 --- a/apps/devops/services/k8s/common/event.go +++ /dev/null @@ -1,63 +0,0 @@ -package common - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "pandax/apps/devops/entity/k8s" -) - -// EventList is an events response structure. -type EventList struct { - ListMeta k8s.ListMeta `json:"listMeta"` - - // List of events from given namespace. - Events []Event `json:"events"` -} - -// Event is a single event representation. -type Event struct { - ObjectMeta k8s.ObjectMeta `json:"objectMeta"` - TypeMeta k8s.TypeMeta `json:"typeMeta"` - - // A human-readable description of the status of related object. - Message string `json:"message"` - - // Component from which the event is generated. - SourceComponent string `json:"sourceComponent"` - - // Host name on which the event is generated. - SourceHost string `json:"sourceHost"` - - // Reference to a piece of an object, which triggered an event. For example - // "spec.containers{name}" refers to container within pod with given name, if no container - // name is specified, for example "spec.containers[2]", then it refers to container with - // index 2 in this pod. - SubObject string `json:"object"` - - // Kind of the referent. - // +optional - SubObjectKind string `json:"objectKind,omitempty"` - - // Name of the referent. - // +optional - SubObjectName string `json:"objectName,omitempty"` - - // Namespace of the referent. - // +optional - SubObjectNamespace string `json:"objectNamespace,omitempty"` - - // The number of times this event has occurred. - Count int32 `json:"count"` - - // The time at which the event was first recorded. - FirstSeen v1.Time `json:"firstSeen"` - - // The time at which the most recent occurrence of this event was recorded. - LastSeen v1.Time `json:"lastSeen"` - - // Short, machine understandable string that gives the reason - // for this event being generated. - Reason string `json:"reason"` - - // Event type (at the moment only normal and warning are supported). - Type string `json:"type"` -} diff --git a/apps/devops/services/k8s/common/namespace.go b/apps/devops/services/k8s/common/namespace.go deleted file mode 100644 index 8b4bd7e..0000000 --- a/apps/devops/services/k8s/common/namespace.go +++ /dev/null @@ -1,47 +0,0 @@ -package common - -import api "k8s.io/api/core/v1" - -// NamespaceQuery is a query for namespaces of a list of objects. -// There's three cases: -// 1. No namespace selected: this means "user namespaces" query, i.e., all except kube-system -// 2. Single namespace selected: this allows for optimizations when querying backends -// 3. More than one namespace selected: resources from all namespaces are queried and then -// filtered here. -type NamespaceQuery struct { - Namespaces []string -} - -// ToRequestParam returns K8s API namespace query for list of objects from this namespaces. -// This is an optimization to query for single namespace if one was selected and for all -// namespaces otherwise. -func (n *NamespaceQuery) ToRequestParam() string { - if len(n.Namespaces) == 1 { - return n.Namespaces[0] - } - return api.NamespaceAll -} - -// Matches returns true when the given namespace matches this query. -func (n *NamespaceQuery) Matches(namespace string) bool { - if len(n.Namespaces) == 0 { - return true - } - - for _, queryNamespace := range n.Namespaces { - if namespace == queryNamespace { - return true - } - } - return false -} - -// NewSameNamespaceQuery creates new namespace query that queries single namespace. -func NewSameNamespaceQuery(namespace string) *NamespaceQuery { - return &NamespaceQuery{[]string{namespace}} -} - -// NewNamespaceQuery creates new query for given namespaces. -func NewNamespaceQuery(namespaces []string) *NamespaceQuery { - return &NamespaceQuery{namespaces} -} diff --git a/apps/devops/services/k8s/common/pod.go b/apps/devops/services/k8s/common/pod.go deleted file mode 100644 index d24e428..0000000 --- a/apps/devops/services/k8s/common/pod.go +++ /dev/null @@ -1,151 +0,0 @@ -package common - -import ( - apps "k8s.io/api/apps/v1" - batch "k8s.io/api/batch/v1" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// FilterDeploymentPodsByOwnerReference returns a subset of pods controlled by given deployment. -func FilterDeploymentPodsByOwnerReference(deployment apps.Deployment, allRS []apps.ReplicaSet, - allPods []v1.Pod) []v1.Pod { - var matchingPods []v1.Pod - for _, rs := range allRS { - if metav1.IsControlledBy(&rs, &deployment) { - matchingPods = append(matchingPods, FilterPodsByControllerRef(&rs, allPods)...) - } - } - - return matchingPods -} - -// FilterPodsByControllerRef returns a subset of pods controlled by given controller resource, excluding deployments. -func FilterPodsByControllerRef(owner metav1.Object, allPods []v1.Pod) []v1.Pod { - var matchingPods []v1.Pod - for _, pod := range allPods { - if metav1.IsControlledBy(&pod, owner) { - matchingPods = append(matchingPods, pod) - } - } - return matchingPods -} - -// GetContainerImages returns container image strings from the given pod spec. -func GetContainerImages(podTemplate *v1.PodSpec) []string { - var containerImages []string - for _, container := range podTemplate.Containers { - containerImages = append(containerImages, container.Image) - } - return containerImages -} - -// GetInitContainerImages returns init container image strings from the given pod spec. -func GetInitContainerImages(podTemplate *v1.PodSpec) []string { - var initContainerImages []string - for _, initContainer := range podTemplate.InitContainers { - initContainerImages = append(initContainerImages, initContainer.Image) - } - return initContainerImages -} - -// FilterPodsForJob returns a list of pods that matches to a job controller's selector -func FilterPodsForJob(job batch.Job, pods []v1.Pod) []v1.Pod { - result := make([]v1.Pod, 0) - for _, pod := range pods { - if pod.Namespace == job.Namespace { - selectorMatch := true - for key, value := range job.Spec.Selector.MatchLabels { - if pod.Labels[key] != value { - selectorMatch = false - break - } - } - if selectorMatch { - result = append(result, pod) - } - } - } - - return result -} - -// GetContainerNames returns the container image name without the version number from the given pod spec. -func GetContainerNames(podTemplate *v1.PodSpec) []string { - var containerNames []string - for _, container := range podTemplate.Containers { - containerNames = append(containerNames, container.Name) - } - return containerNames -} - -// GetInitContainerNames returns the init container image name without the version number from the given pod spec. -func GetInitContainerNames(podTemplate *v1.PodSpec) []string { - var initContainerNames []string - for _, initContainer := range podTemplate.InitContainers { - initContainerNames = append(initContainerNames, initContainer.Name) - } - return initContainerNames -} - -// GetNonduplicateContainerImages returns list of container image strings without duplicates -func GetNonduplicateContainerImages(podList []v1.Pod) []string { - var containerImages []string - for _, pod := range podList { - for _, container := range pod.Spec.Containers { - if noStringInSlice(container.Image, containerImages) { - containerImages = append(containerImages, container.Image) - } - } - } - return containerImages -} - -// GetNonduplicateInitContainerImages returns list of init container image strings without duplicates -func GetNonduplicateInitContainerImages(podList []v1.Pod) []string { - var initContainerImages []string - for _, pod := range podList { - for _, initContainer := range pod.Spec.InitContainers { - if noStringInSlice(initContainer.Image, initContainerImages) { - initContainerImages = append(initContainerImages, initContainer.Image) - } - } - } - return initContainerImages -} - -// GetNonduplicateContainerNames returns list of container names strings without duplicates -func GetNonduplicateContainerNames(podList []v1.Pod) []string { - var containerNames []string - for _, pod := range podList { - for _, container := range pod.Spec.Containers { - if noStringInSlice(container.Name, containerNames) { - containerNames = append(containerNames, container.Name) - } - } - } - return containerNames -} - -// GetNonduplicateInitContainerNames returns list of init container names strings without duplicates -func GetNonduplicateInitContainerNames(podList []v1.Pod) []string { - var initContainerNames []string - for _, pod := range podList { - for _, initContainer := range pod.Spec.InitContainers { - if noStringInSlice(initContainer.Name, initContainerNames) { - initContainerNames = append(initContainerNames, initContainer.Name) - } - } - } - return initContainerNames -} - -//noStringInSlice checks if string in array -func noStringInSlice(str string, array []string) bool { - for _, alreadystr := range array { - if alreadystr == str { - return false - } - } - return true -} diff --git a/apps/devops/services/k8s/common/podinfo.go b/apps/devops/services/k8s/common/podinfo.go deleted file mode 100644 index dd86082..0000000 --- a/apps/devops/services/k8s/common/podinfo.go +++ /dev/null @@ -1,53 +0,0 @@ -package common - -import ( - api "k8s.io/api/core/v1" -) - -// PodInfo represents aggregate information about controller's pods. -type PodInfo struct { - // Number of pods that are created. - Current int32 `json:"current"` - - // Number of pods that are desired. - Desired *int32 `json:"desired,omitempty"` - - // Number of pods that are currently running. - Running int32 `json:"running"` - - // Number of pods that are currently waiting. - Pending int32 `json:"pending"` - - // Number of pods that are failed. - Failed int32 `json:"failed"` - - // Number of pods that are succeeded. - Succeeded int32 `json:"succeeded"` - - // Unique warning messages related to pods in this resource. - Warnings []Event `json:"warnings"` -} - -// GetPodInfo returns aggregate information about a group of pods. -func GetPodInfo(current int32, desired *int32, pods []api.Pod) PodInfo { - result := PodInfo{ - Current: current, - Desired: desired, - Warnings: make([]Event, 0), - } - - for _, pod := range pods { - switch pod.Status.Phase { - case api.PodRunning: - result.Running++ - case api.PodPending: - result.Pending++ - case api.PodFailed: - result.Failed++ - case api.PodSucceeded: - result.Succeeded++ - } - } - - return result -} diff --git a/apps/devops/services/k8s/common/resourcechannels.go b/apps/devops/services/k8s/common/resourcechannels.go deleted file mode 100644 index 794cc86..0000000 --- a/apps/devops/services/k8s/common/resourcechannels.go +++ /dev/null @@ -1,589 +0,0 @@ -package common - -import ( - "context" - batch "k8s.io/api/batch/v1" - batch2 "k8s.io/api/batch/v1beta1" - - apps "k8s.io/api/apps/v1" - v1 "k8s.io/api/core/v1" - extensions "k8s.io/api/extensions/v1beta1" - storage "k8s.io/api/storage/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - client "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" -) - -// ResourceChannels struct holds channels to resource lists. Each list channel is paired with -// an error channel which *must* be read sequentially: first read the list channel and then -// the error channel. -// -// This struct can be used when there are multiple clients that want to process, e.g., a -// list of pods. With this helper, the list can be read only once from the backend and -// distributed asynchronously to clients that need it. -// -// When a channel is nil, it means that no resource list is available for getting. -// -// Each channel pair can be read up to N times. N is specified upon creation of the channels. -type ResourceChannels struct { - - // List and error channels to Replica Sets. - ReplicaSetList ReplicaSetListChannel - - // List and error channels to Deployments. - DeploymentList DeploymentListChannel - - // List and error channels to Pods. - PodList PodListChannel - - // List and error channels to Events. - EventList EventListChannel - - // List and error channels to ConfigMaps. - ConfigMapList ConfigMapListChannel - - // List and error channels to Secrets. - SecretList SecretListChannel - - // List and error channels to PersistentVolumes - PersistentVolumeList PersistentVolumeListChannel - - // List and error channels to PersistentVolumeClaims - PersistentVolumeClaimList PersistentVolumeClaimListChannel - - // List and error channels to StatefulSets. - StatefulSetList StatefulSetListChannel - - // List and error channels to Daemon Sets. - DaemonSetList DaemonSetListChannel - - // List and error channels to Services. - ServiceList ServiceListChannel - - // List and error channels to Jobs. - JobList JobListChannel - - // List and error channels to Cron Jobs. - CronJobList CronJobListChannel - - // List and error channels to StorageClasses - StorageClassList StorageClassListChannel - - // List and error channels to Endpoints. - EndpointList EndpointListChannel - - // List and error channels to Ingresses. - //IngressList IngressListChannel -} - -// EventListChannel is a list and error channels to Events. -type EventListChannel struct { - List chan *v1.EventList - Error chan error -} - -// GetEventListChannel returns a pair of channels to an Event list and errors that both must be read -// numReads times. -func GetEventListChannel(client *client.Clientset, nsQuery *NamespaceQuery, numReads int) EventListChannel { - return GetEventListChannelWithOptions(client, nsQuery, k8s.ListEverything, numReads) -} - -// GetEventListChannelWithOptions is GetEventListChannel plus list options. -func GetEventListChannelWithOptions(client *client.Clientset, nsQuery *NamespaceQuery, options metaV1.ListOptions, numReads int) EventListChannel { - channel := EventListChannel{ - List: make(chan *v1.EventList, numReads), - Error: make(chan error, numReads), - } - - go func() { - // 原options是根据label过滤来过滤Event事件信息, 代码deployment_detail + L78 - // TODO 改成field过滤 - //options.FieldSelector = fmt.Sprintf("involvedObject.name=%v", deploymentName) - list, err := client.CoreV1().Events(nsQuery.ToRequestParam()).List(context.TODO(), options) - var filteredItems []v1.Event - for _, item := range list.Items { - if nsQuery.Matches(item.ObjectMeta.Namespace) { - filteredItems = append(filteredItems, item) - } - } - list.Items = filteredItems - for i := 0; i < numReads; i++ { - channel.List <- list - channel.Error <- err - } - }() - - return channel -} - -// PodListChannel is a list and error channels to Pods. -type PodListChannel struct { - List chan *v1.PodList - Error chan error -} - -// GetPodListChannel returns a pair of channels to a Pod list and errors that both must be read -// numReads times. -func GetPodListChannel(client client.Interface, nsQuery *NamespaceQuery, numReads int) PodListChannel { - return GetPodListChannelWithOptions(client, nsQuery, k8s.ListEverything, numReads) -} - -// GetPodListChannelWithOptions is GetPodListChannel plus listing options. -func GetPodListChannelWithOptions(client client.Interface, nsQuery *NamespaceQuery, options metaV1.ListOptions, numReads int) PodListChannel { - - channel := PodListChannel{ - List: make(chan *v1.PodList, numReads), - Error: make(chan error, numReads), - } - - go func() { - list, err := client.CoreV1().Pods(nsQuery.ToRequestParam()).List(context.TODO(), options) - var filteredItems []v1.Pod - for _, item := range list.Items { - if nsQuery.Matches(item.ObjectMeta.Namespace) { - filteredItems = append(filteredItems, item) - } - } - list.Items = filteredItems - for i := 0; i < numReads; i++ { - channel.List <- list - channel.Error <- err - } - }() - - return channel -} - -// DeploymentListChannel is a list and error channels to Deployments. -type DeploymentListChannel struct { - List chan *apps.DeploymentList - Error chan error -} - -// GetDeploymentListChannel returns a pair of channels to a Deployment list and errors -// that both must be read numReads times. -func GetDeploymentListChannel(client client.Interface, nsQuery *NamespaceQuery, numReads int) DeploymentListChannel { - - channel := DeploymentListChannel{ - List: make(chan *apps.DeploymentList, numReads), - Error: make(chan error, numReads), - } - - go func() { - list, err := client.AppsV1().Deployments(nsQuery.ToRequestParam()).List(context.TODO(), k8s.ListEverything) - var filteredItems []apps.Deployment - for _, item := range list.Items { - if nsQuery.Matches(item.ObjectMeta.Namespace) { - filteredItems = append(filteredItems, item) - } - } - list.Items = filteredItems - for i := 0; i < numReads; i++ { - channel.List <- list - channel.Error <- err - } - }() - - return channel -} - -// ReplicaSetListChannel is a list and error channels to Replica Sets. -type ReplicaSetListChannel struct { - List chan *apps.ReplicaSetList - Error chan error -} - -// GetReplicaSetListChannel returns a pair of channels to a ReplicaSet list and -// errors that both must be read numReads times. -func GetReplicaSetListChannel(client client.Interface, nsQuery *NamespaceQuery, numReads int) ReplicaSetListChannel { - return GetReplicaSetListChannelWithOptions(client, nsQuery, k8s.ListEverything, numReads) -} - -// GetReplicaSetListChannelWithOptions returns a pair of channels to a ReplicaSet list filtered -// by provided options and errors that both must be read numReads times. -func GetReplicaSetListChannelWithOptions(client client.Interface, nsQuery *NamespaceQuery, options metaV1.ListOptions, numReads int) ReplicaSetListChannel { - channel := ReplicaSetListChannel{ - List: make(chan *apps.ReplicaSetList, numReads), - Error: make(chan error, numReads), - } - - go func() { - list, err := client.AppsV1().ReplicaSets(nsQuery.ToRequestParam()). - List(context.TODO(), options) - var filteredItems []apps.ReplicaSet - for _, item := range list.Items { - if nsQuery.Matches(item.ObjectMeta.Namespace) { - filteredItems = append(filteredItems, item) - } - } - list.Items = filteredItems - for i := 0; i < numReads; i++ { - channel.List <- list - channel.Error <- err - } - }() - - return channel -} - -// ConfigMapListChannel is a list and error channels to ConfigMaps. -type ConfigMapListChannel struct { - List chan *v1.ConfigMapList - Error chan error -} - -// GetConfigMapListChannel returns a pair of channels to a ConfigMap list and errors that both must be read -// numReads times. -func GetConfigMapListChannel(client client.Interface, nsQuery *NamespaceQuery, numReads int) ConfigMapListChannel { - - channel := ConfigMapListChannel{ - List: make(chan *v1.ConfigMapList, numReads), - Error: make(chan error, numReads), - } - - go func() { - list, err := client.CoreV1().ConfigMaps(nsQuery.ToRequestParam()).List(context.TODO(), k8s.ListEverything) - var filteredItems []v1.ConfigMap - for _, item := range list.Items { - if nsQuery.Matches(item.ObjectMeta.Namespace) { - filteredItems = append(filteredItems, item) - } - } - list.Items = filteredItems - for i := 0; i < numReads; i++ { - channel.List <- list - channel.Error <- err - } - }() - - return channel -} - -// SecretListChannel is a list and error channels to Secrets. -type SecretListChannel struct { - List chan *v1.SecretList - Error chan error -} - -// GetSecretListChannel returns a pair of channels to a Secret list and errors that -// both must be read numReads times. -func GetSecretListChannel(client client.Interface, nsQuery *NamespaceQuery, numReads int) SecretListChannel { - - channel := SecretListChannel{ - List: make(chan *v1.SecretList, numReads), - Error: make(chan error, numReads), - } - - go func() { - list, err := client.CoreV1().Secrets(nsQuery.ToRequestParam()).List(context.TODO(), k8s.ListEverything) - var filteredItems []v1.Secret - for _, item := range list.Items { - if nsQuery.Matches(item.ObjectMeta.Namespace) { - filteredItems = append(filteredItems, item) - } - } - list.Items = filteredItems - for i := 0; i < numReads; i++ { - channel.List <- list - channel.Error <- err - } - }() - - return channel -} - -// PersistentVolumeListChannel is a list and error channels to PersistentVolumes. -type PersistentVolumeListChannel struct { - List chan *v1.PersistentVolumeList - Error chan error -} - -// GetPersistentVolumeListChannel returns a pair of channels to a PersistentVolume list and errors -// that both must be read numReads times. -func GetPersistentVolumeListChannel(client client.Interface, numReads int) PersistentVolumeListChannel { - channel := PersistentVolumeListChannel{ - List: make(chan *v1.PersistentVolumeList, numReads), - Error: make(chan error, numReads), - } - - go func() { - list, err := client.CoreV1().PersistentVolumes().List(context.TODO(), k8s.ListEverything) - for i := 0; i < numReads; i++ { - channel.List <- list - channel.Error <- err - } - }() - - return channel -} - -// PersistentVolumeClaimListChannel is a list and error channels to PersistentVolumeClaims. -type PersistentVolumeClaimListChannel struct { - List chan *v1.PersistentVolumeClaimList - Error chan error -} - -// GetPersistentVolumeClaimListChannel returns a pair of channels to a PersistentVolumeClaim list -// and errors that both must be read numReads times. -func GetPersistentVolumeClaimListChannel(client client.Interface, nsQuery *NamespaceQuery, numReads int) PersistentVolumeClaimListChannel { - - channel := PersistentVolumeClaimListChannel{ - List: make(chan *v1.PersistentVolumeClaimList, numReads), - Error: make(chan error, numReads), - } - - go func() { - list, err := client.CoreV1().PersistentVolumeClaims(nsQuery.ToRequestParam()).List(context.TODO(), k8s.ListEverything) - for i := 0; i < numReads; i++ { - channel.List <- list - channel.Error <- err - } - }() - - return channel -} - -// StatefulSetListChannel is a list and error channels to StatefulSets. -type StatefulSetListChannel struct { - List chan *apps.StatefulSetList - Error chan error -} - -// GetStatefulSetListChannel returns a pair of channels to a StatefulSet list and errors that both must be read -// numReads times. -func GetStatefulSetListChannel(client client.Interface, nsQuery *NamespaceQuery, numReads int) StatefulSetListChannel { - channel := StatefulSetListChannel{ - List: make(chan *apps.StatefulSetList, numReads), - Error: make(chan error, numReads), - } - - go func() { - statefulSets, err := client.AppsV1().StatefulSets(nsQuery.ToRequestParam()).List(context.TODO(), k8s.ListEverything) - var filteredItems []apps.StatefulSet - for _, item := range statefulSets.Items { - if nsQuery.Matches(item.ObjectMeta.Namespace) { - filteredItems = append(filteredItems, item) - } - } - statefulSets.Items = filteredItems - for i := 0; i < numReads; i++ { - channel.List <- statefulSets - channel.Error <- err - } - }() - - return channel -} - -// DaemonSetListChannel is a list and error channels to Daemon Sets. -type DaemonSetListChannel struct { - List chan *apps.DaemonSetList - Error chan error -} - -// GetDaemonSetListChannel returns a pair of channels to a DaemonSet list and errors that both must be read -// numReads times. -func GetDaemonSetListChannel(client client.Interface, nsQuery *NamespaceQuery, numReads int) DaemonSetListChannel { - channel := DaemonSetListChannel{ - List: make(chan *apps.DaemonSetList, numReads), - Error: make(chan error, numReads), - } - - go func() { - list, err := client.AppsV1().DaemonSets(nsQuery.ToRequestParam()).List(context.TODO(), k8s.ListEverything) - var filteredItems []apps.DaemonSet - for _, item := range list.Items { - if nsQuery.Matches(item.ObjectMeta.Namespace) { - filteredItems = append(filteredItems, item) - } - } - list.Items = filteredItems - for i := 0; i < numReads; i++ { - channel.List <- list - channel.Error <- err - } - }() - - return channel -} - -// ServiceListChannel is a list and error channels to Services. -type ServiceListChannel struct { - List chan *v1.ServiceList - Error chan error -} - -// GetServiceListChannel returns a pair of channels to a Service list and errors that both -// must be read numReads times. -func GetServiceListChannel(client client.Interface, nsQuery *NamespaceQuery, numReads int) ServiceListChannel { - - channel := ServiceListChannel{ - List: make(chan *v1.ServiceList, numReads), - Error: make(chan error, numReads), - } - go func() { - list, err := client.CoreV1().Services(nsQuery.ToRequestParam()).List(context.TODO(), k8s.ListEverything) - var filteredItems []v1.Service - for _, item := range list.Items { - if nsQuery.Matches(item.ObjectMeta.Namespace) { - filteredItems = append(filteredItems, item) - } - } - list.Items = filteredItems - for i := 0; i < numReads; i++ { - channel.List <- list - channel.Error <- err - } - }() - - return channel -} - -// JobListChannel is a list and error channels to Jobs. -type JobListChannel struct { - List chan *batch.JobList - Error chan error -} - -// GetJobListChannel returns a pair of channels to a Job list and errors that both must be read numReads times. -func GetJobListChannel(client client.Interface, nsQuery *NamespaceQuery, numReads int) JobListChannel { - channel := JobListChannel{ - List: make(chan *batch.JobList, numReads), - Error: make(chan error, numReads), - } - - go func() { - list, err := client.BatchV1().Jobs(nsQuery.ToRequestParam()).List(context.TODO(), k8s.ListEverything) - var filteredItems []batch.Job - for _, item := range list.Items { - if nsQuery.Matches(item.ObjectMeta.Namespace) { - filteredItems = append(filteredItems, item) - } - } - list.Items = filteredItems - for i := 0; i < numReads; i++ { - channel.List <- list - channel.Error <- err - } - }() - - return channel -} - -// CronJobListChannel is a list and error channels to Cron Jobs. -type CronJobListChannel struct { - List chan *batch2.CronJobList - Error chan error -} - -// GetCronJobListChannel returns a pair of channels to a Cron Job list and errors that both must be read numReads times. -func GetCronJobListChannel(client client.Interface, nsQuery *NamespaceQuery, numReads int) CronJobListChannel { - channel := CronJobListChannel{ - List: make(chan *batch2.CronJobList, numReads), - Error: make(chan error, numReads), - } - - go func() { - list, err := client.BatchV1beta1().CronJobs(nsQuery.ToRequestParam()).List(context.TODO(), k8s.ListEverything) - var filteredItems []batch2.CronJob - for _, item := range list.Items { - if nsQuery.Matches(item.ObjectMeta.Namespace) { - filteredItems = append(filteredItems, item) - } - } - list.Items = filteredItems - for i := 0; i < numReads; i++ { - channel.List <- list - channel.Error <- err - } - }() - - return channel -} - -// StorageClassListChannel is a list and error channels to storage classes. -type StorageClassListChannel struct { - List chan *storage.StorageClassList - Error chan error -} - -// GetStorageClassListChannel returns a pair of channels to a storage class list and -// errors that both must be read numReads times. -func GetStorageClassListChannel(client client.Interface, numReads int) StorageClassListChannel { - channel := StorageClassListChannel{ - List: make(chan *storage.StorageClassList, numReads), - Error: make(chan error, numReads), - } - - go func() { - list, err := client.StorageV1().StorageClasses().List(context.TODO(), k8s.ListEverything) - for i := 0; i < numReads; i++ { - channel.List <- list - channel.Error <- err - } - }() - - return channel -} - -// EndpointListChannel is a list and error channels to Endpoints. -type EndpointListChannel struct { - List chan *v1.EndpointsList - Error chan error -} - -func GetEndpointListChannel(client client.Interface, nsQuery *NamespaceQuery, numReads int) EndpointListChannel { - return GetEndpointListChannelWithOptions(client, nsQuery, k8s.ListEverything, numReads) -} - -// GetEndpointListChannelWithOptions is GetEndpointListChannel plus list options. -func GetEndpointListChannelWithOptions(client client.Interface, - nsQuery *NamespaceQuery, opt metaV1.ListOptions, numReads int) EndpointListChannel { - channel := EndpointListChannel{ - List: make(chan *v1.EndpointsList, numReads), - Error: make(chan error, numReads), - } - - go func() { - list, err := client.CoreV1().Endpoints(nsQuery.ToRequestParam()).List(context.TODO(), opt) - - for i := 0; i < numReads; i++ { - channel.List <- list - channel.Error <- err - } - }() - - return channel -} - -// IngressListChannel is a list and error channels to Ingresss. -type IngressListChannel struct { - List chan *extensions.IngressList - Error chan error -} - -// GetIngressListChannel returns a pair of channels to an Ingress list and errors that both -// must be read numReads times. -func GetIngressListChannel(client client.Interface, nsQuery *NamespaceQuery, numReads int) IngressListChannel { - - channel := IngressListChannel{ - List: make(chan *extensions.IngressList, numReads), - Error: make(chan error, numReads), - } - go func() { - list, err := client.ExtensionsV1beta1().Ingresses(nsQuery.ToRequestParam()).List(context.TODO(), k8s.ListEverything) - var filteredItems []extensions.Ingress - for _, item := range list.Items { - if nsQuery.Matches(item.ObjectMeta.Namespace) { - filteredItems = append(filteredItems, item) - } - } - list.Items = filteredItems - for i := 0; i < numReads; i++ { - channel.List <- list - channel.Error <- err - } - }() - - return channel -} diff --git a/apps/devops/services/k8s/common/resourcestatus.go b/apps/devops/services/k8s/common/resourcestatus.go deleted file mode 100644 index f6fff67..0000000 --- a/apps/devops/services/k8s/common/resourcestatus.go +++ /dev/null @@ -1,22 +0,0 @@ -package common - -// ResourceStatus provides basic information about resources status on the list. -type ResourceStatus struct { - // Number of resources that are currently in running state. - Running int `json:"running"` - - // Number of resources that are currently in pending state. - Pending int `json:"pending"` - - // Number of resources that are in failed state. - Failed int `json:"failed"` - - // Number of resources that are in succeeded state. - Succeeded int `json:"succeeded"` - - // Number of resources that are in unknown state. - Unknown int `json:"unknown"` - - // Number of resources that are in terminating state. - Terminating int `json:"terminating"` -} diff --git a/apps/devops/services/k8s/common/serviceport.go b/apps/devops/services/k8s/common/serviceport.go deleted file mode 100644 index af30809..0000000 --- a/apps/devops/services/k8s/common/serviceport.go +++ /dev/null @@ -1,24 +0,0 @@ -package common - -import api "k8s.io/api/core/v1" - -// ServicePort is a pair of port and protocol, e.g. a service endpoint. -type ServicePort struct { - // Positive port number. - Port int32 `json:"port"` - - // Protocol name, e.g., TCP or UDP. - Protocol api.Protocol `json:"protocol"` - - // The port on each node on which service is exposed. - NodePort int32 `json:"nodePort"` -} - -// GetServicePorts returns human readable name for the given service ports list. -func GetServicePorts(apiPorts []api.ServicePort) []ServicePort { - var ports []ServicePort - for _, port := range apiPorts { - ports = append(ports, ServicePort{port.Port, port.Protocol, port.NodePort}) - } - return ports -} diff --git a/apps/devops/services/k8s/configmap/configmap.go b/apps/devops/services/k8s/configmap/configmap.go deleted file mode 100644 index 73ea2b2..0000000 --- a/apps/devops/services/k8s/configmap/configmap.go +++ /dev/null @@ -1,102 +0,0 @@ -package configmap - -import ( - "context" - "fmt" - v1 "k8s.io/api/core/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" - "pandax/base/global" -) - -// ConfigMapList contains a list of Config Maps in the cluster. -type ConfigMapList struct { - ListMeta k8s.ListMeta `json:"listMeta"` - - // Unordered list of Config Maps - Items []ConfigMap `json:"items"` -} - -// ConfigMap API resource provides mechanisms to inject containers with configuration data while keeping -// containers agnostic of Kubernetes -type ConfigMap struct { - ObjectMeta k8s.ObjectMeta `json:"objectMeta"` - TypeMeta k8s.TypeMeta `json:"typeMeta"` -} - -// GetConfigMapList returns a list of all ConfigMaps in the cluster. -func GetConfigMapList(client kubernetes.Interface, nsQuery *k8scommon.NamespaceQuery, dsQuery *dataselect.DataSelectQuery) (*ConfigMapList, error) { - global.Log.Info(fmt.Sprintf("Getting list config maps in the namespace %s", nsQuery.ToRequestParam())) - channels := &k8scommon.ResourceChannels{ - ConfigMapList: k8scommon.GetConfigMapListChannel(client, nsQuery, 1), - } - - return GetConfigMapListFromChannels(channels, dsQuery) -} - -// GetConfigMapListFromChannels returns a list of all Config Maps in the cluster reading required resource list once from the channels. -func GetConfigMapListFromChannels(channels *k8scommon.ResourceChannels, dsQuery *dataselect.DataSelectQuery) (*ConfigMapList, error) { - configMaps := <-channels.ConfigMapList.List - err := <-channels.ConfigMapList.Error - if err != nil { - return nil, err - } - - result := toConfigMapList(configMaps.Items, dsQuery) - - return result, nil -} - -func toConfigMap(meta metaV1.ObjectMeta) ConfigMap { - return ConfigMap{ - ObjectMeta: k8s.NewObjectMeta(meta), - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindConfigMap), - } -} - -func toConfigMapList(configMaps []v1.ConfigMap, dsQuery *dataselect.DataSelectQuery) *ConfigMapList { - result := &ConfigMapList{ - Items: make([]ConfigMap, 0), - ListMeta: k8s.ListMeta{TotalItems: len(configMaps)}, - } - - configMapCells, filteredTotal := dataselect.GenericDataSelectWithFilter(toCells(configMaps), dsQuery) - configMaps = fromCells(configMapCells) - result.ListMeta = k8s.ListMeta{TotalItems: filteredTotal} - - for _, item := range configMaps { - result.Items = append(result.Items, toConfigMap(item.ObjectMeta)) - } - - return result -} - -func DeleteConfigMap(client *kubernetes.Clientset, namespace string, name string) error { - global.Log.Info(fmt.Sprintf("请求删除ConfigMap: %v, namespace: %v", name, namespace)) - return client.CoreV1().ConfigMaps(namespace).Delete( - context.TODO(), - name, - metaV1.DeleteOptions{}, - ) -} - -func DeleteCollectionConfigMap(client *kubernetes.Clientset, configMapList []k8s.ConfigMapData) (err error) { - global.Log.Info("批量删除ConfigMap开始") - for _, v := range configMapList { - global.Log.Info(fmt.Sprintf("delete configMap:%v, ns: %v", v.Name, v.Namespace)) - err := client.CoreV1().ConfigMaps(v.Namespace).Delete( - context.TODO(), - v.Name, - metaV1.DeleteOptions{}, - ) - if err != nil { - global.Log.Error(err.Error()) - return err - } - } - global.Log.Info("删除ConfigMap已完成") - return nil -} diff --git a/apps/devops/services/k8s/configmap/configmap_common.go b/apps/devops/services/k8s/configmap/configmap_common.go deleted file mode 100644 index 11ff04a..0000000 --- a/apps/devops/services/k8s/configmap/configmap_common.go +++ /dev/null @@ -1,40 +0,0 @@ -package configmap - -import ( - api "k8s.io/api/core/v1" - "pandax/apps/devops/services/k8s/dataselect" -) - -// The code below allows to perform complex data section on []api.ConfigMap - -type ConfigMapCell api.ConfigMap - -func (self ConfigMapCell) GetProperty(name dataselect.PropertyName) dataselect.ComparableValue { - switch name { - case dataselect.NameProperty: - return dataselect.StdComparableString(self.ObjectMeta.Name) - case dataselect.CreationTimestampProperty: - return dataselect.StdComparableTime(self.ObjectMeta.CreationTimestamp.Time) - case dataselect.NamespaceProperty: - return dataselect.StdComparableString(self.ObjectMeta.Namespace) - default: - // if name is not supported then just return a constant dummy value, sort will have no effect. - return nil - } -} - -func toCells(std []api.ConfigMap) []dataselect.DataCell { - cells := make([]dataselect.DataCell, len(std)) - for i := range std { - cells[i] = ConfigMapCell(std[i]) - } - return cells -} - -func fromCells(cells []dataselect.DataCell) []api.ConfigMap { - std := make([]api.ConfigMap, len(cells)) - for i := range std { - std[i] = api.ConfigMap(cells[i].(ConfigMapCell)) - } - return std -} diff --git a/apps/devops/services/k8s/configmap/configmap_detail.go b/apps/devops/services/k8s/configmap/configmap_detail.go deleted file mode 100644 index 7fac928..0000000 --- a/apps/devops/services/k8s/configmap/configmap_detail.go +++ /dev/null @@ -1,42 +0,0 @@ -package configmap - -import ( - "context" - "fmt" - "pandax/base/global" - - v1 "k8s.io/api/core/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" -) - -// ConfigMapDetail API resource provides mechanisms to inject containers with configuration data while keeping -// containers agnostic of Kubernetes -type ConfigMapDetail struct { - // Extends list item structure. - ConfigMap `json:",inline"` - - // Data contains the configuration data. - // Each key must be a valid DNS_SUBDOMAIN with an optional leading dot. - Data map[string]string `json:"data,omitempty"` -} - -// GetConfigMapDetail returns detailed information about a config map -func GetConfigMapDetail(client kubernetes.Interface, namespace, name string) (*ConfigMapDetail, error) { - global.Log.Info(fmt.Sprintf("Getting details of %s config map in %s namespace", name, namespace)) - - rawConfigMap, err := client.CoreV1().ConfigMaps(namespace).Get(context.TODO(), name, metaV1.GetOptions{}) - - if err != nil { - return nil, err - } - - return getConfigMapDetail(rawConfigMap), nil -} - -func getConfigMapDetail(rawConfigMap *v1.ConfigMap) *ConfigMapDetail { - return &ConfigMapDetail{ - ConfigMap: toConfigMap(rawConfigMap.ObjectMeta), - Data: rawConfigMap.Data, - } -} diff --git a/apps/devops/services/k8s/controller/controller.go b/apps/devops/services/k8s/controller/controller.go deleted file mode 100644 index d12bfb6..0000000 --- a/apps/devops/services/k8s/controller/controller.go +++ /dev/null @@ -1,304 +0,0 @@ -package controller - -import ( - "context" - "fmt" - apps "k8s.io/api/apps/v1" - batch "k8s.io/api/batch/v1" - v1 "k8s.io/api/core/v1" - meta "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - client "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/event" - "strings" -) - -// ResourceOwner is an structure representing resource owner, it may be Replication Controller, -// Daemon Set, Job etc. -type ResourceOwner struct { - ObjectMeta k8s.ObjectMeta `json:"objectMeta"` - TypeMeta k8s.TypeMeta `json:"typeMeta"` - Pods k8scommon.PodInfo `json:"pods"` - ContainerImages []string `json:"containerImages"` - InitContainerImages []string `json:"initContainerImages"` -} - -// LogSources is a structure that represents all log files (all combinations of pods and container) -// from a higher level controller (such as ReplicaSet). -type LogSources struct { - ContainerNames []string `json:"containerNames"` - InitContainerNames []string `json:"initContainerNames"` - PodNames []string `json:"podNames"` -} - -// ResourceController is an interface, that allows to perform operations on resource controller. To -// instantiate it use NewResourceController and pass object reference to it. It may be extended to -// provide more detailed set of functions. -type ResourceController interface { - // UID returns UID of controlled resource. - UID() types.UID - // Get is a method, that returns ResourceOwner object. - Get(allPods []v1.Pod, allEvents []v1.Event) ResourceOwner - // Returns all log sources of controlled resource (e.g. a list of containers and pods for a replica set). - GetLogSources(allPods []v1.Pod) LogSources -} - -// NewResourceController creates instance of ResourceController based on given reference. It allows -// to convert owner/created by references to real objects. -func NewResourceController(ref meta.OwnerReference, namespace string, client client.Interface) ( - ResourceController, error) { - switch strings.ToLower(ref.Kind) { - case k8s.ResourceKindJob: - job, err := client.BatchV1().Jobs(namespace).Get(context.TODO(), ref.Name, meta.GetOptions{}) - if err != nil { - return nil, err - } - return JobController(*job), nil - case k8s.ResourceKindPod: - pod, err := client.CoreV1().Pods(namespace).Get(context.TODO(), ref.Name, meta.GetOptions{}) - if err != nil { - return nil, err - } - return PodController(*pod), nil - case k8s.ResourceKindReplicaSet: - rs, err := client.AppsV1().ReplicaSets(namespace).Get(context.TODO(), ref.Name, meta.GetOptions{}) - if err != nil { - return nil, err - } - return ReplicaSetController(*rs), nil - case k8s.ResourceKindReplicationController: - rc, err := client.CoreV1().ReplicationControllers(namespace).Get(context.TODO(), ref.Name, meta.GetOptions{}) - if err != nil { - return nil, err - } - return ReplicationControllerController(*rc), nil - case k8s.ResourceKindDaemonSet: - ds, err := client.AppsV1().DaemonSets(namespace).Get(context.TODO(), ref.Name, meta.GetOptions{}) - if err != nil { - return nil, err - } - return DaemonSetController(*ds), nil - case k8s.ResourceKindStatefulSet: - ss, err := client.AppsV1().StatefulSets(namespace).Get(context.TODO(), ref.Name, meta.GetOptions{}) - if err != nil { - return nil, err - } - return StatefulSetController(*ss), nil - default: - return nil, fmt.Errorf("unknown reference kind: %s", ref.Kind) - } -} - -// JobController is an alias-type for Kubernetes API Job type. It allows to provide custom set of -// functions for already existing type. -type JobController batch.Job - -// Get is an implementation of Get method from ResourceController interface. -func (self JobController) Get(allPods []v1.Pod, allEvents []v1.Event) ResourceOwner { - matchingPods := k8scommon.FilterPodsForJob(batch.Job(self), allPods) - podInfo := k8scommon.GetPodInfo(self.Status.Active, self.Spec.Completions, matchingPods) - podInfo.Warnings = event.GetPodsEventWarnings(allEvents, matchingPods) - - return ResourceOwner{ - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindJob), - ObjectMeta: k8s.NewObjectMeta(self.ObjectMeta), - Pods: podInfo, - ContainerImages: k8scommon.GetContainerImages(&self.Spec.Template.Spec), - InitContainerImages: k8scommon.GetInitContainerImages(&self.Spec.Template.Spec), - } -} - -// UID is an implementation of UID method from ResourceController interface. -func (self JobController) UID() types.UID { - return batch.Job(self).UID -} - -// GetLogSources is an implementation of the GetLogSources method from ResourceController interface. -func (self JobController) GetLogSources(allPods []v1.Pod) LogSources { - controlledPods := k8scommon.FilterPodsForJob(batch.Job(self), allPods) - return LogSources{ - PodNames: getPodNames(controlledPods), - ContainerNames: k8scommon.GetContainerNames(&self.Spec.Template.Spec), - InitContainerNames: k8scommon.GetInitContainerNames(&self.Spec.Template.Spec), - } -} - -type PodController v1.Pod - -// Get is an implementation of Get method from ResourceController interface. -func (self PodController) Get(allPods []v1.Pod, allEvents []v1.Event) ResourceOwner { - matchingPods := k8scommon.FilterPodsByControllerRef(&self, allPods) - podInfo := k8scommon.GetPodInfo(int32(len(matchingPods)), nil, matchingPods) // Pods should not desire any Pods - podInfo.Warnings = event.GetPodsEventWarnings(allEvents, matchingPods) - - return ResourceOwner{ - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindPod), - ObjectMeta: k8s.NewObjectMeta(self.ObjectMeta), - Pods: podInfo, - ContainerImages: k8scommon.GetNonduplicateContainerImages(matchingPods), - InitContainerImages: k8scommon.GetNonduplicateInitContainerImages(matchingPods), - } -} - -// UID is an implementation of UID method from ResourceController interface. -func (self PodController) UID() types.UID { - return v1.Pod(self).UID -} - -// GetLogSources is an implementation of the GetLogSources method from ResourceController interface. -func (self PodController) GetLogSources(allPods []v1.Pod) LogSources { - controlledPods := k8scommon.FilterPodsByControllerRef(&self, allPods) - return LogSources{ - PodNames: getPodNames(controlledPods), - ContainerNames: k8scommon.GetNonduplicateContainerNames(controlledPods), - InitContainerNames: k8scommon.GetNonduplicateInitContainerNames(controlledPods), - } -} - -// ReplicaSetController is an alias-type for Kubernetes API Replica Set type. It allows to provide -// custom set of functions for already existing type. -type ReplicaSetController apps.ReplicaSet - -// Get is an implementation of Get method from ResourceController interface. -func (self ReplicaSetController) Get(allPods []v1.Pod, allEvents []v1.Event) ResourceOwner { - matchingPods := k8scommon.FilterPodsByControllerRef(&self, allPods) - podInfo := k8scommon.GetPodInfo(self.Status.Replicas, self.Spec.Replicas, matchingPods) - podInfo.Warnings = event.GetPodsEventWarnings(allEvents, matchingPods) - - return ResourceOwner{ - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindReplicaSet), - ObjectMeta: k8s.NewObjectMeta(self.ObjectMeta), - Pods: podInfo, - ContainerImages: k8scommon.GetContainerImages(&self.Spec.Template.Spec), - InitContainerImages: k8scommon.GetInitContainerImages(&self.Spec.Template.Spec), - } -} - -// UID is an implementation of UID method from ResourceController interface. -func (self ReplicaSetController) UID() types.UID { - return apps.ReplicaSet(self).UID -} - -// GetLogSources is an implementation of the GetLogSources method from ResourceController interface. -func (self ReplicaSetController) GetLogSources(allPods []v1.Pod) LogSources { - controlledPods := k8scommon.FilterPodsByControllerRef(&self, allPods) - return LogSources{ - PodNames: getPodNames(controlledPods), - ContainerNames: k8scommon.GetContainerNames(&self.Spec.Template.Spec), - InitContainerNames: k8scommon.GetInitContainerNames(&self.Spec.Template.Spec), - } -} - -// ReplicationControllerController is an alias-type for Kubernetes API Replication Controller type. -// It allows to provide custom set of functions for already existing type. -type ReplicationControllerController v1.ReplicationController - -// Get is an implementation of Get method from ResourceController interface. -func (self ReplicationControllerController) Get(allPods []v1.Pod, - allEvents []v1.Event) ResourceOwner { - matchingPods := k8scommon.FilterPodsByControllerRef(&self, allPods) - podInfo := k8scommon.GetPodInfo(self.Status.Replicas, self.Spec.Replicas, matchingPods) - podInfo.Warnings = event.GetPodsEventWarnings(allEvents, matchingPods) - - return ResourceOwner{ - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindReplicationController), - ObjectMeta: k8s.NewObjectMeta(self.ObjectMeta), - Pods: podInfo, - ContainerImages: k8scommon.GetContainerImages(&self.Spec.Template.Spec), - InitContainerImages: k8scommon.GetInitContainerImages(&self.Spec.Template.Spec), - } -} - -// UID is an implementation of UID method from ResourceController interface. -func (self ReplicationControllerController) UID() types.UID { - return v1.ReplicationController(self).UID -} - -// GetLogSources is an implementation of the GetLogSources method from ResourceController interface. -func (self ReplicationControllerController) GetLogSources(allPods []v1.Pod) LogSources { - controlledPods := k8scommon.FilterPodsByControllerRef(&self, allPods) - return LogSources{ - PodNames: getPodNames(controlledPods), - ContainerNames: k8scommon.GetContainerNames(&self.Spec.Template.Spec), - InitContainerNames: k8scommon.GetInitContainerNames(&self.Spec.Template.Spec), - } -} - -// DaemonSetController is an alias-type for Kubernetes API Daemon Set type. It allows to provide -// custom set of functions for already existing type. -type DaemonSetController apps.DaemonSet - -// Get is an implementation of Get method from ResourceController interface. -func (self DaemonSetController) Get(allPods []v1.Pod, allEvents []v1.Event) ResourceOwner { - matchingPods := k8scommon.FilterPodsByControllerRef(&self, allPods) - podInfo := k8scommon.GetPodInfo(self.Status.CurrentNumberScheduled, - &self.Status.DesiredNumberScheduled, matchingPods) - podInfo.Warnings = event.GetPodsEventWarnings(allEvents, matchingPods) - - return ResourceOwner{ - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindDaemonSet), - ObjectMeta: k8s.NewObjectMeta(self.ObjectMeta), - Pods: podInfo, - ContainerImages: k8scommon.GetContainerImages(&self.Spec.Template.Spec), - InitContainerImages: k8scommon.GetInitContainerImages(&self.Spec.Template.Spec), - } -} - -// UID is an implementation of UID method from ResourceController interface. -func (self DaemonSetController) UID() types.UID { - return apps.DaemonSet(self).UID -} - -// GetLogSources is an implementation of the GetLogSources method from ResourceController interface. -func (self DaemonSetController) GetLogSources(allPods []v1.Pod) LogSources { - controlledPods := k8scommon.FilterPodsByControllerRef(&self, allPods) - return LogSources{ - PodNames: getPodNames(controlledPods), - ContainerNames: k8scommon.GetContainerNames(&self.Spec.Template.Spec), - InitContainerNames: k8scommon.GetInitContainerNames(&self.Spec.Template.Spec), - } -} - -// StatefulSetController is an alias-type for Kubernetes API Stateful Set type. It allows to provide -// custom set of functions for already existing type. -type StatefulSetController apps.StatefulSet - -// Get is an implementation of Get method from ResourceController interface. -func (self StatefulSetController) Get(allPods []v1.Pod, allEvents []v1.Event) ResourceOwner { - matchingPods := k8scommon.FilterPodsByControllerRef(&self, allPods) - podInfo := k8scommon.GetPodInfo(self.Status.Replicas, self.Spec.Replicas, matchingPods) - podInfo.Warnings = event.GetPodsEventWarnings(allEvents, matchingPods) - - return ResourceOwner{ - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindStatefulSet), - ObjectMeta: k8s.NewObjectMeta(self.ObjectMeta), - Pods: podInfo, - ContainerImages: k8scommon.GetContainerImages(&self.Spec.Template.Spec), - InitContainerImages: k8scommon.GetInitContainerImages(&self.Spec.Template.Spec), - } -} - -// UID is an implementation of UID method from ResourceController interface. -func (self StatefulSetController) UID() types.UID { - return apps.StatefulSet(self).UID -} - -// GetLogSources is an implementation of the GetLogSources method from ResourceController interface. -func (self StatefulSetController) GetLogSources(allPods []v1.Pod) LogSources { - controlledPods := k8scommon.FilterPodsByControllerRef(&self, allPods) - return LogSources{ - PodNames: getPodNames(controlledPods), - ContainerNames: k8scommon.GetContainerNames(&self.Spec.Template.Spec), - InitContainerNames: k8scommon.GetInitContainerNames(&self.Spec.Template.Spec), - } -} - -func getPodNames(pods []v1.Pod) []string { - names := make([]string, 0) - for _, pod := range pods { - names = append(names, pod.Name) - } - return names -} diff --git a/apps/devops/services/k8s/controller/controller_test.go b/apps/devops/services/k8s/controller/controller_test.go deleted file mode 100644 index 9727454..0000000 --- a/apps/devops/services/k8s/controller/controller_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package controller - -import ( - "pandax/apps/devops/entity/k8s" - "reflect" - "testing" - - v1 "k8s.io/api/core/v1" - meta "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes/fake" -) - -func TestGetPodNames(t *testing.T) { - cases := []struct { - pods []v1.Pod - expectedNames []string - }{ - { - pods: nil, - expectedNames: []string{}, - }, - { - pods: []v1.Pod{newPod("a"), newPod("b")}, - expectedNames: []string{"a", "b"}, - }, - } - - for _, c := range cases { - actual := getPodNames(c.pods) - if !reflect.DeepEqual(actual, c.expectedNames) { - t.Errorf("GetPodNames(%+v) == %+v, expected %+v", - c.pods, actual, c.expectedNames) - } - } - -} - -func TestNewResourceController(t *testing.T) { - pod := v1.Pod{ - TypeMeta: meta.TypeMeta{ - Kind: "pod", - APIVersion: "v1", - }, - ObjectMeta: meta.ObjectMeta{ - Name: "test-name", - Namespace: "default", - }} - cli := fake.NewSimpleClientset(&pod) - - ctrl, err := NewResourceController( - meta.OwnerReference{ - Kind: k8s.ResourceKindPod, - Name: "test-name", - }, "default", cli) - - if err != nil { - t.Fatal("Returned Error finding pod") - } - podCtrl, ok := ctrl.(PodController) - if !ok { - t.Fatal("Returned value is not pod controller") - } - if podCtrl.Name != "test-name" { - t.Fatal("Returned invalid pod name") - } - NewResourceController( - meta.OwnerReference{ - Kind: k8s.ResourceKindPod, - Name: "test-name", - }, "default", fake.NewSimpleClientset()) - podCtrl.Get([]v1.Pod{pod}, []v1.Event{}) - podCtrl.UID() - podCtrl.GetLogSources([]v1.Pod{pod}) -} - -func newPod(name string) v1.Pod { - return v1.Pod{ObjectMeta: meta.ObjectMeta{Name: name}} -} diff --git a/apps/devops/services/k8s/cronjob/cronjob.go b/apps/devops/services/k8s/cronjob/cronjob.go deleted file mode 100644 index 7d00f0e..0000000 --- a/apps/devops/services/k8s/cronjob/cronjob.go +++ /dev/null @@ -1,117 +0,0 @@ -package cronjob - -import ( - "context" - "fmt" - "pandax/base/global" - - "k8s.io/api/batch/v1beta1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - client "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" -) - -// CronJobList contains a list of CronJobs in the cluster. -type CronJobList struct { - ListMeta k8s.ListMeta `json:"listMeta"` - Items []CronJob `json:"items"` - - // Basic information about resources status on the list. - Status k8scommon.ResourceStatus `json:"status"` -} - -// CronJob is a presentation layer view of Kubernetes Cron Job resource. -type CronJob struct { - ObjectMeta k8s.ObjectMeta `json:"objectMeta"` - TypeMeta k8s.TypeMeta `json:"typeMeta"` - Schedule string `json:"schedule"` - Suspend *bool `json:"suspend"` - Active int `json:"active"` - LastSchedule *metav1.Time `json:"lastSchedule"` - - // ContainerImages holds a list of the CronJob images. - ContainerImages []string `json:"containerImages"` -} - -// GetCronJobList returns a list of all CronJobs in the cluster. -func GetCronJobList(client client.Interface, nsQuery *k8scommon.NamespaceQuery, dsQuery *dataselect.DataSelectQuery) (*CronJobList, error) { - global.Log.Info("Getting list of all cron jobs in the cluster") - - channels := &k8scommon.ResourceChannels{ - CronJobList: k8scommon.GetCronJobListChannel(client, nsQuery, 1), - } - - return GetCronJobListFromChannels(channels, dsQuery) -} - -// GetCronJobListFromChannels returns a list of all CronJobs in the cluster reading required resource -// list once from the channels. -func GetCronJobListFromChannels(channels *k8scommon.ResourceChannels, dsQuery *dataselect.DataSelectQuery) (*CronJobList, error) { - - cronJobs := <-channels.CronJobList.List - err := <-channels.CronJobList.Error - if err != nil { - return nil, err - } - - cronJobList := toCronJobList(cronJobs.Items, dsQuery) - cronJobList.Status = getStatus(cronJobs) - return cronJobList, nil -} - -func toCronJobList(cronJobs []v1beta1.CronJob, dsQuery *dataselect.DataSelectQuery) *CronJobList { - - list := &CronJobList{ - Items: make([]CronJob, 0), - ListMeta: k8s.ListMeta{TotalItems: len(cronJobs)}, - } - - cronJobCells, filteredTotal := dataselect.GenericDataSelectWithFilter(ToCells(cronJobs), dsQuery) - cronJobs = FromCells(cronJobCells) - list.ListMeta = k8s.ListMeta{TotalItems: filteredTotal} - - for _, cronJob := range cronJobs { - list.Items = append(list.Items, toCronJob(&cronJob)) - } - - return list -} - -func toCronJob(cj *v1beta1.CronJob) CronJob { - return CronJob{ - ObjectMeta: k8s.NewObjectMeta(cj.ObjectMeta), - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindCronJob), - Schedule: cj.Spec.Schedule, - Suspend: cj.Spec.Suspend, - Active: len(cj.Status.Active), - LastSchedule: cj.Status.LastScheduleTime, - ContainerImages: getContainerImages(cj), - } -} - -func DeleteCronJob(client *client.Clientset, namespace, name string) (err error) { - // for k8s version < 1.21.0, use batch/v1beta1 - // if you use BatchV1 Will report an error: the server could not find the requested resource - // BatchV1beta1 - return client.BatchV1beta1().CronJobs(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{}) -} - -func DeleteCollectionCronJob(client *client.Clientset, jobList []k8s.JobData) (err error) { - global.Log.Info("批量删除cronjob开始") - for _, v := range jobList { - global.Log.Info(fmt.Sprintf("delete cronjob:%v, ns: %v", v.Name, v.Namespace)) - err := client.BatchV1beta1().CronJobs(v.Namespace).Delete( - context.TODO(), - v.Name, - metav1.DeleteOptions{}, - ) - if err != nil { - global.Log.Error(err.Error()) - return err - } - } - global.Log.Info("删除cronjob已完成") - return nil -} diff --git a/apps/devops/services/k8s/cronjob/cronjob_common.go b/apps/devops/services/k8s/cronjob/cronjob_common.go deleted file mode 100644 index 22d9925..0000000 --- a/apps/devops/services/k8s/cronjob/cronjob_common.go +++ /dev/null @@ -1,69 +0,0 @@ -package cronjob - -import ( - batchv1beta1 "k8s.io/api/batch/v1beta1" - "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" -) - -// The code below allows to perform complex data section on []batch.CronJob - -type CronJobCell batchv1beta1.CronJob - -func (self CronJobCell) GetProperty(name dataselect.PropertyName) dataselect.ComparableValue { - switch name { - case dataselect.NameProperty: - return dataselect.StdComparableString(self.ObjectMeta.Name) - case dataselect.CreationTimestampProperty: - return dataselect.StdComparableTime(self.ObjectMeta.CreationTimestamp.Time) - case dataselect.NamespaceProperty: - return dataselect.StdComparableString(self.ObjectMeta.Namespace) - default: - // if name is not supported then just return a constant dummy value, sort will have no effect. - return nil - } -} - -func ToCells(std []batchv1beta1.CronJob) []dataselect.DataCell { - cells := make([]dataselect.DataCell, len(std)) - for i := range std { - cells[i] = CronJobCell(std[i]) - } - return cells -} - -func FromCells(cells []dataselect.DataCell) []batchv1beta1.CronJob { - std := make([]batchv1beta1.CronJob, len(cells)) - for i := range std { - std[i] = batchv1beta1.CronJob(cells[i].(CronJobCell)) - } - return std -} - -func getStatus(list *batchv1beta1.CronJobList) common.ResourceStatus { - info := common.ResourceStatus{} - if list == nil { - return info - } - - for _, cronJob := range list.Items { - if cronJob.Spec.Suspend != nil && !(*cronJob.Spec.Suspend) { - info.Running++ - } else { - info.Failed++ - } - } - - return info -} - -func getContainerImages(cronJob *batchv1beta1.CronJob) []string { - podSpec := cronJob.Spec.JobTemplate.Spec.Template.Spec - result := make([]string, 0) - - for _, container := range podSpec.Containers { - result = append(result, container.Image) - } - - return result -} diff --git a/apps/devops/services/k8s/cronjob/cronjob_detail.go b/apps/devops/services/k8s/cronjob/cronjob_detail.go deleted file mode 100644 index a4f50b7..0000000 --- a/apps/devops/services/k8s/cronjob/cronjob_detail.go +++ /dev/null @@ -1,45 +0,0 @@ -package cronjob - -import ( - "context" - "encoding/json" - "fmt" - batch2 "k8s.io/api/batch/v1beta1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" -) - -// CronJobDetail contains Cron Job details. -type CronJobDetail struct { - // Extends list item structure. - CronJob `json:",inline"` - - ConcurrencyPolicy string `json:"concurrencyPolicy"` - - StartingDeadLineSeconds *int64 `json:"startingDeadlineSeconds"` - - JobList *JobList `json:"jobList"` -} - -// GetCronJobDetail gets Cron Job details. -func GetCronJobDetail(client *kubernetes.Clientset, namespace, name string) (*CronJobDetail, error) { - - rawObject, err := client.BatchV1beta1().CronJobs(namespace).Get(context.TODO(), name, metaV1.GetOptions{}) - if err != nil { - return nil, err - } - j, _ := json.Marshal(rawObject) - fmt.Printf("cronJob: %s\n", j) - cj := toCronJobDetail(rawObject, client, name) - return &cj, nil -} - -func toCronJobDetail(cj *batch2.CronJob, client *kubernetes.Clientset, name string) CronJobDetail { - - return CronJobDetail{ - CronJob: toCronJob(cj), - ConcurrencyPolicy: string(cj.Spec.ConcurrencyPolicy), - StartingDeadLineSeconds: cj.Spec.StartingDeadlineSeconds, - JobList: getJobList(client, cj, name), - } -} diff --git a/apps/devops/services/k8s/cronjob/job_list.go b/apps/devops/services/k8s/cronjob/job_list.go deleted file mode 100644 index 52dd0a0..0000000 --- a/apps/devops/services/k8s/cronjob/job_list.go +++ /dev/null @@ -1,60 +0,0 @@ -package cronjob - -import ( - "context" - "pandax/base/global" - - "go.uber.org/zap" - batch "k8s.io/api/batch/v1" - batch2 "k8s.io/api/batch/v1beta1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/job" - "strings" -) - -type JobList struct { - ListMeta k8s.ListMeta `json:"listMeta"` - - // Basic information about resources status on the list. - Status k8scommon.ResourceStatus `json:"status"` - - // Unordered list of Pods. - Jobs []job.Job `json:"jobs"` -} - -func getJobList(client *kubernetes.Clientset, cj *batch2.CronJob, name string) (jo *JobList) { - - jobData, err := client.BatchV1().Jobs(cj.Namespace).List(context.TODO(), metaV1.ListOptions{}) - if err != nil { - global.Log.Error("Get a job list exception from the cronjob", zap.Any("err", err)) - } - jobList := JobList{ - Jobs: make([]job.Job, 0), - } - jobList.ListMeta = k8s.ListMeta{TotalItems: len(jobData.Items)} - for _, j := range jobData.Items { - if strings.Contains(j.Name, name) { - jobList.Jobs = append(jobList.Jobs, toJob(&j)) - jobList.ListMeta = k8s.ListMeta{ - TotalItems: len(jobList.Jobs), - } - } - } - - return &jobList -} - -func toJob(j *batch.Job) job.Job { - return job.Job{ - ObjectMeta: k8s.NewObjectMeta(j.ObjectMeta), - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindJob), - ContainerImages: k8scommon.GetContainerImages(&j.Spec.Template.Spec), - InitContainerImages: k8scommon.GetInitContainerImages(&j.Spec.Template.Spec), - JobStatus: job.GetJobStatus(j), - PodStatus: job.GetPodStatus(j), - Parallelism: j.Spec.Parallelism, - } -} diff --git a/apps/devops/services/k8s/daemonset/daemonset.go b/apps/devops/services/k8s/daemonset/daemonset.go deleted file mode 100644 index f3e9364..0000000 --- a/apps/devops/services/k8s/daemonset/daemonset.go +++ /dev/null @@ -1,191 +0,0 @@ -package daemonset - -import ( - "context" - "fmt" - "pandax/base/global" - - "go.uber.org/zap" - apps "k8s.io/api/apps/v1" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" - "pandax/apps/devops/services/k8s/event" - "time" -) - -// DaemonSetList contains a list of Daemon Sets in the cluster. -type DaemonSetList struct { - ListMeta k8s.ListMeta `json:"listMeta"` - DaemonSets []DaemonSet `json:"daemonSets"` - Status k8scommon.ResourceStatus `json:"status"` - - // List of non-critical errors, that occurred during resource retrieval. - Errors []error `json:"errors"` -} - -// DaemonSet plus zero or more Kubernetes services that target the Daemon Set. -type DaemonSet struct { - ObjectMeta k8s.ObjectMeta `json:"objectMeta"` - TypeMeta k8s.TypeMeta `json:"typeMeta"` - Pods k8scommon.PodInfo `json:"podInfo"` - Strategy apps.DaemonSetUpdateStrategy `json:"strategy"` - // Status information on the statefulSet - StatusInfo `json:"statusInfo"` - ContainerImages []string `json:"containerImages"` - InitContainerImages []string `json:"initContainerImages"` -} - -// StatusInfo is the status information of the daemonset -type StatusInfo struct { - - // readyReplicas is the number of Pods created by the DaemonSet controller that have a Ready Condition. - Ready int32 `json:"ready,omitempty"` - - // currentReplicas is the number of Pods created by the DaemonSet controller from the DaemonSet version - // indicated by currentRevision. - Current int32 `json:"current,omitempty"` - - // updatedReplicas is the number of Pods created by the DaemonSet controller from the DaemonSet version - // indicated by updateRevision. - Updated int32 `json:"updated,omitempty"` - // Total number of available pods (ready for at least minReadySeconds) targeted by this daemonset. - // This is an alpha field and requires enabling DaemonSetMinReadySeconds feature gate. - // Remove omitempty when graduating to beta - // +optional - Available int32 `json:"available,omitempty"` - - Unavailable int32 `json:"unavailable"` -} - -func GetDaemonSetList(client *kubernetes.Clientset, nsQuery *k8scommon.NamespaceQuery, dsQuery *dataselect.DataSelectQuery) (*DaemonSetList, error) { - channels := &k8scommon.ResourceChannels{ - DaemonSetList: k8scommon.GetDaemonSetListChannel(client, nsQuery, 1), - ServiceList: k8scommon.GetServiceListChannel(client, nsQuery, 1), - PodList: k8scommon.GetPodListChannel(client, nsQuery, 1), - EventList: k8scommon.GetEventListChannel(client, nsQuery, 1), - } - - return GetDaemonSetListFromChannels(channels, dsQuery) -} - -// GetDaemonSetListFromChannels returns a list of all Daemon Set in the cluster -// reading required resource list once from the channels. -func GetDaemonSetListFromChannels(channels *k8scommon.ResourceChannels, dsQuery *dataselect.DataSelectQuery) (*DaemonSetList, error) { - - daemonSets := <-channels.DaemonSetList.List - err := <-channels.DaemonSetList.Error - if err != nil { - return nil, err - } - - pods := <-channels.PodList.List - err = <-channels.PodList.Error - if err != nil { - return nil, err - } - - events := <-channels.EventList.List - err = <-channels.EventList.Error - if err != nil { - return nil, err - } - - dsList := toDaemonSetList(daemonSets.Items, pods.Items, events.Items, dsQuery) - dsList.Status = getStatus(daemonSets, pods.Items, events.Items) - return dsList, nil -} - -func toDaemonSetList(daemonSets []apps.DaemonSet, pods []v1.Pod, events []v1.Event, dsQuery *dataselect.DataSelectQuery) *DaemonSetList { - - daemonSetList := &DaemonSetList{ - DaemonSets: make([]DaemonSet, 0), - ListMeta: k8s.ListMeta{TotalItems: len(daemonSets)}, - } - - dsCells, filteredTotal := dataselect.GenericDataSelectWithFilter(ToCells(daemonSets), dsQuery) - daemonSets = FromCells(dsCells) - daemonSetList.ListMeta = k8s.ListMeta{TotalItems: filteredTotal} - - for _, daemonSet := range daemonSets { - daemonSetList.DaemonSets = append(daemonSetList.DaemonSets, toDaemonSet(daemonSet, pods, events)) - } - - return daemonSetList -} - -func toDaemonSet(daemonSet apps.DaemonSet, pods []v1.Pod, events []v1.Event) DaemonSet { - matchingPods := k8scommon.FilterPodsByControllerRef(&daemonSet, pods) - podInfo := k8scommon.GetPodInfo(daemonSet.Status.CurrentNumberScheduled, &daemonSet.Status.DesiredNumberScheduled, matchingPods) - podInfo.Warnings = event.GetPodsEventWarnings(events, matchingPods) - return DaemonSet{ - ObjectMeta: k8s.NewObjectMeta(daemonSet.ObjectMeta), - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindDaemonSet), - Pods: podInfo, - Strategy: daemonSet.Spec.UpdateStrategy, - StatusInfo: GetStatusInfo(&daemonSet.Status), - ContainerImages: k8scommon.GetContainerImages(&daemonSet.Spec.Template.Spec), - InitContainerImages: k8scommon.GetInitContainerImages(&daemonSet.Spec.Template.Spec), - } -} - -// GetStatusInfo is used to get the status information from the *apps.DaemonSetStatus -func GetStatusInfo(daemonSetStatus *apps.DaemonSetStatus) StatusInfo { - return StatusInfo{ - Updated: daemonSetStatus.UpdatedNumberScheduled, - Available: daemonSetStatus.NumberAvailable, - Ready: daemonSetStatus.NumberReady, - Current: daemonSetStatus.CurrentNumberScheduled, - Unavailable: daemonSetStatus.NumberUnavailable, - } -} - -func DeleteCollectionDaemonSet(client *kubernetes.Clientset, daemonSetList []k8s.DaemonSetData) (err error) { - global.Log.Info("批量删除daemonset开始") - for _, v := range daemonSetList { - global.Log.Info(fmt.Sprintf("delete statefulset:%v, ns: %v", v.Name, v.Namespace)) - err := client.AppsV1().DaemonSets(v.Namespace).Delete( - context.TODO(), - v.Name, - metav1.DeleteOptions{}, - ) - if err != nil { - global.Log.Error(err.Error()) - return err - } - } - global.Log.Info("删除daemonset已完成") - return nil -} - -func DeleteDaemonSet(client *kubernetes.Clientset, namespace, name string) (err error) { - global.Log.Info(fmt.Sprintf("请求删除单个daemonset:%v, namespace: %v", name, namespace)) - return client.AppsV1().DaemonSets(namespace).Delete( - context.TODO(), - name, - metav1.DeleteOptions{}, - ) -} - -func RestartDaemonSet(client *kubernetes.Clientset, namespace, name string) (err error) { - global.Log.Info(fmt.Sprintf("下发应用重启指令, 名称空间:%v, 守护进程集:%v", namespace, name)) - data := fmt.Sprintf(`{"spec":{"template":{"metadata":{"annotations":{"kubectl.kubernetes.io/restartedAt":"%s"}}}}}`, time.Now().String()) - _, err = client.AppsV1().DaemonSets(namespace).Patch( - context.Background(), - name, - types.StrategicMergePatchType, - []byte(data), - metav1.PatchOptions{ - FieldManager: "kubectl-rollout", - }) - - if err != nil { - global.Log.Error("应用重启失败", zap.Any("err: ", err)) - return err - } - return nil -} diff --git a/apps/devops/services/k8s/daemonset/daemonset_common.go b/apps/devops/services/k8s/daemonset/daemonset_common.go deleted file mode 100644 index d9aaf97..0000000 --- a/apps/devops/services/k8s/daemonset/daemonset_common.go +++ /dev/null @@ -1,67 +0,0 @@ -package daemonset - -import ( - apps "k8s.io/api/apps/v1" - v1 "k8s.io/api/core/v1" - "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" - "pandax/apps/devops/services/k8s/event" -) - -// The code below allows to perform complex data section on Daemon Set - -type DaemonSetCell apps.DaemonSet - -func (self DaemonSetCell) GetProperty(name dataselect.PropertyName) dataselect.ComparableValue { - switch name { - case dataselect.NameProperty: - return dataselect.StdComparableString(self.ObjectMeta.Name) - case dataselect.CreationTimestampProperty: - return dataselect.StdComparableTime(self.ObjectMeta.CreationTimestamp.Time) - case dataselect.NamespaceProperty: - return dataselect.StdComparableString(self.ObjectMeta.Namespace) - default: - // if name is not supported then just return a constant dummy value, sort will have no effect. - return nil - } -} - -func getStatus(list *apps.DaemonSetList, pods []v1.Pod, events []v1.Event) common.ResourceStatus { - info := common.ResourceStatus{} - if list == nil { - return info - } - - for _, daemonSet := range list.Items { - matchingPods := common.FilterPodsByControllerRef(&daemonSet, pods) - podInfo := common.GetPodInfo(daemonSet.Status.CurrentNumberScheduled, - &daemonSet.Status.DesiredNumberScheduled, matchingPods) - warnings := event.GetPodsEventWarnings(events, matchingPods) - - if len(warnings) > 0 { - info.Failed++ - } else if podInfo.Pending > 0 { - info.Pending++ - } else { - info.Running++ - } - } - - return info -} - -func ToCells(std []apps.DaemonSet) []dataselect.DataCell { - cells := make([]dataselect.DataCell, len(std)) - for i := range std { - cells[i] = DaemonSetCell(std[i]) - } - return cells -} - -func FromCells(cells []dataselect.DataCell) []apps.DaemonSet { - std := make([]apps.DaemonSet, len(cells)) - for i := range std { - std[i] = apps.DaemonSet(cells[i].(DaemonSetCell)) - } - return std -} diff --git a/apps/devops/services/k8s/daemonset/daemonset_detail.go b/apps/devops/services/k8s/daemonset/daemonset_detail.go deleted file mode 100644 index 04f95c2..0000000 --- a/apps/devops/services/k8s/daemonset/daemonset_detail.go +++ /dev/null @@ -1,57 +0,0 @@ -package daemonset - -import ( - "context" - "fmt" - "pandax/base/global" - - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/service" -) - -// DaemonSetDetail represents detailed information about a Daemon Set. -type DaemonSetDetail struct { - // Extends list item structure. - DaemonSet `json:",inline"` - - LabelSelector *v1.LabelSelector `json:"labelSelector,omitempty"` - - PodList *PodList `json:"podList"` - - SvcList *service.ServiceList `json:"svcList"` -} - -// GetDaemonSetDetail Returns detailed information about the given daemon set in the given namespace. -func GetDaemonSetDetail(client *kubernetes.Clientset, namespace, name string) (*DaemonSetDetail, error) { - - global.Log.Info(fmt.Sprintf("Getting details of %s daemon set in %s namespace", name, namespace)) - daemonSet, err := client.AppsV1().DaemonSets(namespace).Get(context.TODO(), name, metaV1.GetOptions{}) - if err != nil { - return nil, err - } - - channels := &k8scommon.ResourceChannels{ - EventList: k8scommon.GetEventListChannel(client, k8scommon.NewSameNamespaceQuery(namespace), 1), - PodList: k8scommon.GetPodListChannel(client, k8scommon.NewSameNamespaceQuery(namespace), 1), - } - - eventList := <-channels.EventList.List - if err := <-channels.EventList.Error; err != nil { - return nil, err - } - - podList := <-channels.PodList.List - if err := <-channels.PodList.Error; err != nil { - return nil, err - } - serviceList, _ := service.GetToService(client, namespace, name) - return &DaemonSetDetail{ - DaemonSet: toDaemonSet(*daemonSet, podList.Items, eventList.Items), - LabelSelector: daemonSet.Spec.Selector, - PodList: getDaemonSetToPod(client, *daemonSet), - SvcList: serviceList, - }, nil -} diff --git a/apps/devops/services/k8s/daemonset/daemonset_pods.go b/apps/devops/services/k8s/daemonset/daemonset_pods.go deleted file mode 100644 index 96ee250..0000000 --- a/apps/devops/services/k8s/daemonset/daemonset_pods.go +++ /dev/null @@ -1,50 +0,0 @@ -package daemonset - -import ( - "context" - "pandax/base/global" - - "go.uber.org/zap" - apps "k8s.io/api/apps/v1" - v1 "k8s.io/api/core/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/event" - "pandax/apps/devops/services/k8s/pods" -) - -type PodList struct { - ListMeta k8s.ListMeta `json:"listMeta"` - - // Basic information about resources status on the list. - Status k8scommon.ResourceStatus `json:"status"` - - // Unordered list of Pods. - Pods []pods.Pod `json:"pods"` -} - -func getDaemonSetToPod(client *kubernetes.Clientset, daemonSet apps.DaemonSet) (po *PodList) { - - selector, err := metaV1.LabelSelectorAsSelector(daemonSet.Spec.Selector) - if err != nil { - return nil - } - options := metaV1.ListOptions{LabelSelector: selector.String()} - - podData, err := client.CoreV1().Pods(daemonSet.Namespace).List(context.TODO(), options) - if err != nil { - global.Log.Error("Get a pod exception from the statefulSet", zap.Any("err", err)) - } - podList := PodList{ - Pods: make([]pods.Pod, 0), - } - podList.ListMeta = k8s.ListMeta{TotalItems: len(podData.Items)} - for _, pod := range podData.Items { - warnings := event.GetPodsEventWarnings(nil, []v1.Pod{pod}) - podDetail := pods.ToPod(&pod, warnings) - podList.Pods = append(podList.Pods, podDetail) - } - return &podList -} diff --git a/apps/devops/services/k8s/dataselect/dataselect.go b/apps/devops/services/k8s/dataselect/dataselect.go deleted file mode 100644 index 0a1e48d..0000000 --- a/apps/devops/services/k8s/dataselect/dataselect.go +++ /dev/null @@ -1,142 +0,0 @@ -package dataselect - -import ( - "sort" -) - -// GenericDataCell describes the interface of the data cell that contains all the necessary methods needed to perform -// complex data selection -// GenericDataSelect takes a list of these interfaces and performs selection operation. -// Therefore as long as the list is composed of GenericDataCells you can perform any data selection! -type DataCell interface { - // GetPropertyAtIndex returns the property of this data cell. - // Value returned has to have Compare method which is required by Sort functionality of DataSelect. - GetProperty(PropertyName) ComparableValue -} - -// ComparableValue hold any value that can be compared to its own kind. -type ComparableValue interface { - // Compares self with other value. Returns 1 if other value is smaller, 0 if they are the same, -1 if other is larger. - Compare(ComparableValue) int - // Returns true if self value contains or is equal to other value, false otherwise. - Contains(ComparableValue) bool -} - -// SelectableData contains all the required data to perform data selection. -// It implements sort.Interface so its sortable under sort.Sort -// You can use its Select method to get selected GenericDataCell list. -type DataSelector struct { - // GenericDataList hold generic data cells that are being selected. - GenericDataList []DataCell - // DataSelectQuery holds instructions for data select. - DataSelectQuery *DataSelectQuery -} - -// GenericDataSelectWithFilter 获取 GenericDataCells 和 DataSelectQuery 的列表,并按照 dsQuery 的指示返回选定的数据。 -func GenericDataSelectWithFilter(dataList []DataCell, dsQuery *DataSelectQuery) ([]DataCell, int) { - SelectableData := DataSelector{ - GenericDataList: dataList, - DataSelectQuery: dsQuery, - } - // Pipeline is Filter -> Sort -> CollectMetrics -> Paginate - filtered := SelectableData.Filter() - filteredTotal := len(filtered.GenericDataList) - processed := filtered.Sort().Paginate() - return processed.GenericDataList, filteredTotal -} - -// Filter the data inside as instructed by DataSelectQuery and returns itself to allow method chaining. -func (self *DataSelector) Filter() *DataSelector { - filteredList := []DataCell{} - - for _, c := range self.GenericDataList { - matches := true - for _, filterBy := range self.DataSelectQuery.FilterQuery.FilterByList { - v := c.GetProperty(filterBy.Property) - if v == nil || !v.Contains(filterBy.Value) { - matches = false - break - } - } - if matches { - filteredList = append(filteredList, c) - } - } - - self.GenericDataList = filteredList - return self -} - -// Implementation of sort.Interface so that we can use built-in sort function (sort.Sort) for sorting SelectableData - -// Len returns the length of data inside SelectableData. -func (self DataSelector) Len() int { return len(self.GenericDataList) } - -// Swap swaps 2 indices inside SelectableData. -func (self DataSelector) Swap(i, j int) { - self.GenericDataList[i], self.GenericDataList[j] = self.GenericDataList[j], self.GenericDataList[i] -} - -// Less compares 2 indices inside SelectableData and returns true if first index is larger. -func (self DataSelector) Less(i, j int) bool { - for _, sortBy := range self.DataSelectQuery.SortQuery.SortByList { - a := self.GenericDataList[i].GetProperty(sortBy.Property) - b := self.GenericDataList[j].GetProperty(sortBy.Property) - // ignore sort completely if property name not found - if a == nil || b == nil { - break - } - cmp := a.Compare(b) - if cmp == 0 { // values are the same. Just continue to next sortBy - continue - } else { // values different - return (cmp == -1 && sortBy.Ascending) || (cmp == 1 && !sortBy.Ascending) - } - } - return false -} - -// Sort sorts the data inside as instructed by DataSelectQuery and returns itself to allow method chaining. -func (self *DataSelector) Sort() *DataSelector { - sort.Sort(*self) - return self -} - -// Paginates the data inside as instructed by DataSelectQuery and returns itself to allow method chaining. -func (self *DataSelector) Paginate() *DataSelector { - pQuery := self.DataSelectQuery.PaginationQuery - dataList := self.GenericDataList - startIndex, endIndex := pQuery.GetPaginationSettings(len(dataList)) - - // Return all items if provided settings do not meet requirements - if !pQuery.IsValidPagination() { - return self - } - // Return no items if requested page does not exist - if !pQuery.IsPageAvailable(len(self.GenericDataList), startIndex) { - self.GenericDataList = []DataCell{} - return self - } - - self.GenericDataList = dataList[startIndex:endIndex] - return self -} - -// IsValidPagination returns true if pagination has non negative parameters -func (p *PaginationQuery) IsValidPagination() bool { - return p.ItemsPerPage >= 0 && p.Page >= 0 -} - -// IsPageAvailable returns true if at least one element can be placed on page. False otherwise -func (p *PaginationQuery) IsPageAvailable(itemsCount, startingIndex int) bool { - return itemsCount > startingIndex && p.ItemsPerPage > 0 -} - -// GenericDataSelect takes a list of GenericDataCells and DataSelectQuery and returns selected data as instructed by dsQuery. -func GenericDataSelect(dataList []DataCell, dsQuery *DataSelectQuery) []DataCell { - SelectableData := DataSelector{ - GenericDataList: dataList, - DataSelectQuery: dsQuery, - } - return SelectableData.Sort().Paginate().GenericDataList -} diff --git a/apps/devops/services/k8s/dataselect/dataselectquery.go b/apps/devops/services/k8s/dataselect/dataselectquery.go deleted file mode 100644 index 742756b..0000000 --- a/apps/devops/services/k8s/dataselect/dataselectquery.go +++ /dev/null @@ -1,118 +0,0 @@ -package dataselect - -// DataSelectQuery is options for GenericDataSelect which takes []GenericDataCell and returns selected data. -// Can be extended to include any kind of selection - for example filtering. -// Currently included only Pagination and Sort options. -type DataSelectQuery struct { - PaginationQuery *PaginationQuery - SortQuery *SortQuery - FilterQuery *FilterQuery -} - -// PaginationQuery structure represents pagination settings -type PaginationQuery struct { - // How many items per page should be returned - ItemsPerPage int - // Number of page that should be returned when pagination is applied to the list - Page int -} - -// SortQuery holds options for sort functionality of data select. -type SortQuery struct { - SortByList []SortBy -} - -// SortBy holds the name of the property that should be sorted and whether order should be ascending or descending. -type SortBy struct { - Property PropertyName - Ascending bool -} - -type FilterQuery struct { - FilterByList []FilterBy -} - -type FilterBy struct { - Property PropertyName - Value ComparableValue -} - -var NoFilter = &FilterQuery{ - FilterByList: []FilterBy{}, -} - -// NoSort is as option for no sort. -var NoSort = &SortQuery{ - SortByList: []SortBy{}, -} - -// NewFilterQuery takes raw filter options list and returns FilterQuery object. For example: -// ["parameter1", "value1", "parameter2", "value2"] - means that the data should be filtered by -// parameter1 equals value1 and parameter2 equals value2 -func NewFilterQuery(filterByListRaw []string) *FilterQuery { - if filterByListRaw == nil || len(filterByListRaw)%2 == 1 { - return NoFilter - } - filterByList := []FilterBy{} - for i := 0; i+1 < len(filterByListRaw); i += 2 { - propertyName := filterByListRaw[i] - propertyValue := filterByListRaw[i+1] - filterBy := FilterBy{ - Property: PropertyName(propertyName), - Value: StdComparableString(propertyValue), - } - // Add to the filter options. - filterByList = append(filterByList, filterBy) - } - return &FilterQuery{ - FilterByList: filterByList, - } -} - -// NewSortQuery takes raw sort options list and returns SortQuery object. For example: -// ["a", "parameter1", "d", "parameter2"] - means that the data should be sorted by -// parameter1 (ascending) and later - for results that return equal under parameter 1 sort - by parameter2 (descending) -func NewSortQuery(sortByListRaw []string) *SortQuery { - if sortByListRaw == nil || len(sortByListRaw)%2 == 1 { - // Empty sort list or invalid (odd) length - return NoSort - } - sortByList := []SortBy{} - for i := 0; i+1 < len(sortByListRaw); i += 2 { - // parse order option - var ascending bool - orderOption := sortByListRaw[i] - if orderOption == "a" { - ascending = true - } else if orderOption == "d" { - ascending = false - } else { - // Invalid order option. Only ascending (a), descending (d) options are supported - return NoSort - } - - // parse property name - propertyName := sortByListRaw[i+1] - sortBy := SortBy{ - Property: PropertyName(propertyName), - Ascending: ascending, - } - // Add to the sort options. - sortByList = append(sortByList, sortBy) - } - return &SortQuery{ - SortByList: sortByList, - } -} - -// NewDataSelectQuery creates DataSelectQuery object from simpler data select queries. -func NewDataSelectQuery(paginationQuery *PaginationQuery, sortQuery *SortQuery, filterQuery *FilterQuery) *DataSelectQuery { - return &DataSelectQuery{ - PaginationQuery: paginationQuery, - SortQuery: sortQuery, - FilterQuery: filterQuery, - } -} - -// DefaultDataSelect downloads first 10 items from page 1 with no sort and no metrics. -var DefaultDataSelect = NewDataSelectQuery(DefaultPagination, NoSort, NoFilter) diff --git a/apps/devops/services/k8s/dataselect/pagination.go b/apps/devops/services/k8s/dataselect/pagination.go deleted file mode 100644 index df65d16..0000000 --- a/apps/devops/services/k8s/dataselect/pagination.go +++ /dev/null @@ -1,28 +0,0 @@ -package dataselect - -// By default backend pagination will not be applied. -var NoPagination = NewPaginationQuery(-1, -1) - -// No items will be returned -var EmptyPagination = NewPaginationQuery(0, 0) - -// Returns 10 items from page 1 -var DefaultPagination = NewPaginationQuery(10, 0) - -// NewPaginationQuery return pagination query structure based on given parameters -func NewPaginationQuery(itemsPerPage, page int) *PaginationQuery { - return &PaginationQuery{itemsPerPage, page} -} - -// GetPaginationSettings based on number of items and pagination query parameters returns start -// and end index that can be used to return paginated list of items. -func (p *PaginationQuery) GetPaginationSettings(itemsCount int) (startIndex int, endIndex int) { - startIndex = p.ItemsPerPage * p.Page - endIndex = startIndex + p.ItemsPerPage - - if endIndex > itemsCount { - endIndex = itemsCount - } - - return startIndex, endIndex -} diff --git a/apps/devops/services/k8s/dataselect/propertyname.go b/apps/devops/services/k8s/dataselect/propertyname.go deleted file mode 100644 index fb66c3e..0000000 --- a/apps/devops/services/k8s/dataselect/propertyname.go +++ /dev/null @@ -1,17 +0,0 @@ -package dataselect - -// PropertyName is used to get the value of certain property of data cell. -// For example if we want to get the namespace of certain Deployment we can use DeploymentCell.GetProperty(NamespaceProperty) -type PropertyName string - -// List of all property names supported by the UI. -const ( - NameProperty = "name" - CreationTimestampProperty = "creationTimestamp" - NamespaceProperty = "namespace" - StatusProperty = "status" - TypeProperty = "type" - FirstSeenProperty = "firstSeen" - LastSeenProperty = "lastSeen" - ReasonProperty = "reason" -) diff --git a/apps/devops/services/k8s/dataselect/stdcomparabletypes.go b/apps/devops/services/k8s/dataselect/stdcomparabletypes.go deleted file mode 100644 index 07c203e..0000000 --- a/apps/devops/services/k8s/dataselect/stdcomparabletypes.go +++ /dev/null @@ -1,38 +0,0 @@ -package dataselect - -import ( - "strings" - "time" -) - -type StdComparableString string - -func (self StdComparableString) Compare(otherV ComparableValue) int { - other := otherV.(StdComparableString) - return strings.Compare(string(self), string(other)) -} - -func (self StdComparableString) Contains(otherV ComparableValue) bool { - other := otherV.(StdComparableString) - return strings.Contains(string(self), string(other)) -} - -type StdComparableTime time.Time - -func (self StdComparableTime) Compare(otherV ComparableValue) int { - other := otherV.(StdComparableTime) - return ints64Compare(time.Time(self).Unix(), time.Time(other).Unix()) -} - -func (self StdComparableTime) Contains(otherV ComparableValue) bool { - return self.Compare(otherV) == 0 -} - -func ints64Compare(a, b int64) int { - if a > b { - return 1 - } else if a == b { - return 0 - } - return -1 -} diff --git a/apps/devops/services/k8s/deployment/deployment.go b/apps/devops/services/k8s/deployment/deployment.go deleted file mode 100644 index cbcb8e2..0000000 --- a/apps/devops/services/k8s/deployment/deployment.go +++ /dev/null @@ -1,376 +0,0 @@ -package deployment - -import ( - "context" - "pandax/base/global" - "pandax/base/utils" - - "fmt" - - "go.uber.org/zap" - apps "k8s.io/api/apps/v1" - autoscalingv1 "k8s.io/api/autoscaling/v1" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes" - deploymentutil "k8s.io/kubectl/pkg/util/deployment" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" - "pandax/apps/devops/services/k8s/event" - "time" -) - -// DeploymentList contains a list of Deployments in the cluster. -type DeploymentList struct { - ListMeta k8s.ListMeta `json:"listMeta"` - // Basic information about resources status on the list. - Status k8scommon.ResourceStatus `json:"status"` - // Unordered list of Deployments. - Deployments []Deployment `json:"deployments"` -} - -// Deployment is a presentation layer view of Kubernetes Deployment resource. This means -// it is Deployment plus additional augmented data we can get from other sources -// (like services that target the same pods). -type Deployment struct { - ObjectMeta k8s.ObjectMeta `json:"objectMeta"` - TypeMeta k8s.TypeMeta `json:"typeMeta"` - - // Aggregate information about pods belonging to this Deployment. - Pods k8scommon.PodInfo `json:"pods"` - - // Container images of the Deployment. - ContainerImages []string `json:"containerImages"` - - // Init Container images of the Deployment. - InitContainerImages []string `json:"initContainerImages"` - - // Deployment replicas ready - DeploymentStatus DeploymentStatus `json:"deploymentStatus"` -} - -type DeploymentStatus struct { - // Total number of non-terminated pods targeted by this deployment (their labels match the selector). - // +optional - Replicas int32 `json:"replicas"` - - // Total number of non-terminated pods targeted by this deployment that have the desired template spec. - // +optional - UpdatedReplicas int32 `json:"updatedReplicas"` - - // Total number of ready pods targeted by this deployment. - // +optional - ReadyReplicas int32 `json:"readyReplicas"` - - // Total number of available pods (ready for at least minReadySeconds) targeted by this deployment. - // +optional - AvailableReplicas int32 `json:"availableReplicas"` - - // Total number of unavailable pods targeted by this deployment. This is the total number of - // pods that are still required for the deployment to have 100% available capacity. They may - // either be pods that are running but not yet available or pods that still have not been created. - // +optional - UnavailableReplicas int32 `json:"unavailableReplicas"` -} - -// GetDeploymentList 返回集群中所有deployment的列表 -func GetDeploymentList(client *kubernetes.Clientset, nsQuery *k8scommon.NamespaceQuery, dsQuery *dataselect.DataSelectQuery) (*DeploymentList, error) { - global.Log.Info("Getting list of all deployments in the cluster") - - channels := &k8scommon.ResourceChannels{ - DeploymentList: k8scommon.GetDeploymentListChannel(client, nsQuery, 1), - PodList: k8scommon.GetPodListChannel(client, nsQuery, 1), - EventList: k8scommon.GetEventListChannel(client, nsQuery, 1), - ReplicaSetList: k8scommon.GetReplicaSetListChannel(client, nsQuery, 1), - } - - return GetDeploymentListFromChannels(channels, dsQuery) -} - -// GetDeploymentListFromChannels returns a list of all Deployments in the cluster -// reading required resource list once from the channels. -func GetDeploymentListFromChannels(channels *k8scommon.ResourceChannels, dsQuery *dataselect.DataSelectQuery) (*DeploymentList, error) { - - deployments := <-channels.DeploymentList.List - err := <-channels.DeploymentList.Error - if err != nil { - return nil, err - } - - pods := <-channels.PodList.List - err = <-channels.PodList.Error - if err != nil { - return nil, err - } - - events := <-channels.EventList.List - err = <-channels.EventList.Error - if err != nil { - return nil, err - } - - rs := <-channels.ReplicaSetList.List - err = <-channels.ReplicaSetList.Error - if err != nil { - return nil, err - } - - deploymentList := toDeploymentList(deployments.Items, pods.Items, events.Items, rs.Items, dsQuery) - deploymentList.Status = getStatus(deployments, rs.Items, pods.Items, events.Items) - return deploymentList, nil -} - -func toDeploymentList(deployments []apps.Deployment, pods []v1.Pod, events []v1.Event, rs []apps.ReplicaSet, dsQuery *dataselect.DataSelectQuery) *DeploymentList { - - deploymentList := &DeploymentList{ - Deployments: make([]Deployment, 0), - ListMeta: k8s.ListMeta{TotalItems: len(deployments)}, - } - - deploymentCells, filteredTotal := dataselect.GenericDataSelectWithFilter(toCells(deployments), dsQuery) - deployments = fromCells(deploymentCells) - deploymentList.ListMeta = k8s.ListMeta{TotalItems: filteredTotal} - - for _, deployment := range deployments { - deploymentList.Deployments = append(deploymentList.Deployments, toDeployment(&deployment, rs, pods, events)) - } - - return deploymentList -} - -func toDeployment(deployment *apps.Deployment, rs []apps.ReplicaSet, pods []v1.Pod, events []v1.Event) Deployment { - matchingPods := k8scommon.FilterDeploymentPodsByOwnerReference(*deployment, rs, pods) - podInfo := k8scommon.GetPodInfo(deployment.Status.Replicas, deployment.Spec.Replicas, matchingPods) - podInfo.Warnings = event.GetPodsEventWarnings(events, matchingPods) - - return Deployment{ - ObjectMeta: k8s.NewObjectMeta(deployment.ObjectMeta), - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindDeployment), - Pods: podInfo, - ContainerImages: k8scommon.GetContainerImages(&deployment.Spec.Template.Spec), - InitContainerImages: k8scommon.GetInitContainerImages(&deployment.Spec.Template.Spec), - DeploymentStatus: getDeploymentStatus(deployment), - } -} - -func getDeploymentStatus(deployment *apps.Deployment) DeploymentStatus { - - return DeploymentStatus{ - Replicas: deployment.Status.Replicas, - UpdatedReplicas: deployment.Status.UpdatedReplicas, - ReadyReplicas: deployment.Status.ReadyReplicas, - AvailableReplicas: deployment.Status.AvailableReplicas, - UnavailableReplicas: deployment.Status.UnavailableReplicas, - } -} - -func DeleteCollectionDeployment(client *kubernetes.Clientset, deploymentList []k8s.RemoveDeploymentData) (err error) { - global.Log.Info("批量删除deployment开始") - for _, v := range deploymentList { - global.Log.Info(fmt.Sprintf("delete deployment:%v, ns: %v", v.DeploymentName, v.Namespace)) - err := client.AppsV1().Deployments(v.Namespace).Delete( - context.TODO(), - v.DeploymentName, - metav1.DeleteOptions{}, - ) - if err != nil { - global.Log.Error(err.Error()) - return err - } - } - global.Log.Info("删除deployment已完成") - return nil -} - -func DeleteDeployment(client *kubernetes.Clientset, ns string, deploymentName string) (err error) { - global.Log.Info(fmt.Sprintf("请求删除单个deployment:%v, namespace: %v", deploymentName, ns)) - return client.AppsV1().Deployments(ns).Delete( - context.TODO(), - deploymentName, - metav1.DeleteOptions{}, - ) -} - -func ScaleDeployment(client *kubernetes.Clientset, ns string, deploymentName string, scaleNumber int32) (err error) { - - global.Log.Info(fmt.Sprintf("start scale of %v deployment in %v namespace", deploymentName, ns)) - - scaleData, err := client.AppsV1().Deployments(ns).GetScale( - context.TODO(), - deploymentName, - metav1.GetOptions{}, - ) - - global.Log.Info(fmt.Sprintf("The deployment has changed from %v to %v", scaleData.Spec.Replicas, scaleNumber)) - - scale := autoscalingv1.Scale{ - TypeMeta: scaleData.TypeMeta, - ObjectMeta: scaleData.ObjectMeta, - Spec: autoscalingv1.ScaleSpec{Replicas: scaleNumber}, - Status: scaleData.Status, - } - _, err = client.AppsV1().Deployments(ns).UpdateScale( - context.TODO(), - deploymentName, - &scale, - metav1.UpdateOptions{}, - ) - - if err != nil { - global.Log.Error("扩缩容出现异常", zap.Any("err: ", err)) - return err - } - return nil -} - -func RestartDeployment(client *kubernetes.Clientset, deploymentName string, namespace string) (err error) { - global.Log.Info(fmt.Sprintf("下发应用重启指令, 名称空间:%v, 无状态应用:%v", namespace, deploymentName)) - data := fmt.Sprintf(`{"spec":{"template":{"metadata":{"annotations":{"kubectl.kubernetes.io/restartedAt":"%s"}}}}}`, time.Now().String()) - _, err = client.AppsV1().Deployments(namespace).Patch( - context.Background(), - deploymentName, - types.StrategicMergePatchType, - []byte(data), - metav1.PatchOptions{ - FieldManager: "kubectl-rollout", - }) - - if err != nil { - global.Log.Error("应用重启失败", zap.Any("err: ", err)) - return err - } - return nil -} - -func RollbackDeployment(client *kubernetes.Clientset, deploymentName string, namespace string, reVersion int64) (err error) { - /* - 该Api方法已移除, 不推荐使用 client.ExtensionsV1beta1().Deployments(namespace).Rollback(v1beta1.DeploymentRollback{}) - https://github.com/kubernetes/kubernetes/pull/59970 - - - Because of the removal of /rollback endpoint in apps/v1.Deployments, the example and kubectl, if switched to apps/v1.Deployments, need to do the rollback logic themselves. That includes: - - 1.List all ReplicaSets the Deployment owns - 2.Find the ReplicaSet of a specific revision - 3.Copy that ReplicaSet's template back to the Deployment's template - - The rollback logic currently lives in Deployment controller code, which still uses extensions/v1beta1 Deployment client: - https://github.com/kubernetes/kubernetes/blob/ecc5eb67d965295db95ba2df5f3d3ff43a258a05/pkg/controller/deployment/rollback.go#L30-L69 - */ - global.Log.Info(fmt.Sprintf("应用:%v, 所属空间:%v, 版本回滚到%v", deploymentName, namespace, reVersion)) - if reVersion < 0 { - return revisionNotFoundErr(reVersion) - } - - deployment, err := client.AppsV1().Deployments(namespace).Get(context.TODO(), deploymentName, metav1.GetOptions{}) - if err != nil { - return fmt.Errorf("failed to retrieve Deployment %s: %v", deploymentName, err) - } - if deployment.Spec.Paused { - return fmt.Errorf("skipped rollback (deployment \"%s\" is paused)", deployment.Name) - } - // If rollback revision is 0, rollback to the last revision - if reVersion == 0 { - global.Log.Warn("传递回滚版本号是:0, 默认回退上一次版本!") - rsForRevision, err := deploymentRevision(deployment, client, reVersion) - if err != nil { - return err - } - - for k, _ := range rsForRevision.Annotations { - if k == "deployment.kubernetes.io/revision" { - deployment.Spec.Template = rsForRevision.Spec.Template - if _, rollbackErr := client.AppsV1().Deployments(namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{}); rollbackErr != nil { - global.Log.Error("版本回退失败", zap.Any("err: ", err)) - return rollbackErr - } - global.Log.Info("The rollback task was executed successfully") - return nil - } - } - } - - selector, err := metav1.LabelSelectorAsSelector(deployment.Spec.Selector) - if err != nil { - return err - } - options := metav1.ListOptions{LabelSelector: selector.String()} - - replicaSetList, err := client.AppsV1().ReplicaSets(namespace).List(context.TODO(), options) - if err != nil { - return err - } - if len(replicaSetList.Items) <= 1 { - return revisionNotFoundErr(reVersion) - } - - for _, v := range replicaSetList.Items { - // reVersion = nginx-56656dc477 Or reVersion = 5 - // v.ObjectMeta.Name Or v.Annotations["deployment.kubernetes.io/revision"] == reVersion - currentVersion := utils.ParseStringToInt64(v.Annotations["deployment.kubernetes.io/revision"]) - if currentVersion == reVersion { - deployment.Spec.Template = v.Spec.Template - if _, rollbackErr := client.AppsV1().Deployments(namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{}); rollbackErr != nil { - global.Log.Error("版本回退失败", zap.Any("err: ", err)) - return rollbackErr - } - global.Log.Info("The rollback task was executed successfully") - return nil - } - } - return nil -} - -func deploymentRevision(deployment *apps.Deployment, c kubernetes.Interface, toRevision int64) (revision *apps.ReplicaSet, err error) { - - _, allOldRSs, newRS, err := deploymentutil.GetAllReplicaSets(deployment, c.AppsV1()) - if err != nil { - return nil, fmt.Errorf("failed to retrieve replica sets from deployment %s: %v", deployment.Name, err) - } - allRSs := allOldRSs - if newRS != nil { - allRSs = append(allRSs, newRS) - } - - var ( - latestReplicaSet *apps.ReplicaSet - latestRevision = int64(-1) - previousReplicaSet *apps.ReplicaSet - previousRevision = int64(-1) - ) - for _, rs := range allRSs { - if v, err := deploymentutil.Revision(rs); err == nil { - if toRevision == 0 { - if latestRevision < v { - // newest one we've seen so far - previousRevision = latestRevision - previousReplicaSet = latestReplicaSet - latestRevision = v - latestReplicaSet = rs - } else if previousRevision < v { - // second newest one we've seen so far - previousRevision = v - previousReplicaSet = rs - } - } else if toRevision == v { - return rs, nil - } - } - } - - if toRevision > 0 { - return nil, revisionNotFoundErr(toRevision) - } - - if previousReplicaSet == nil { - return nil, fmt.Errorf("no rollout history found for deployment %q", deployment.Name) - } - return previousReplicaSet, nil -} - -func revisionNotFoundErr(r int64) error { - global.Log.Warn("没有找到可回滚的版本!") - return fmt.Errorf("unable to find specified revision %v in history", r) -} diff --git a/apps/devops/services/k8s/deployment/deployment_common.go b/apps/devops/services/k8s/deployment/deployment_common.go deleted file mode 100644 index 3552720..0000000 --- a/apps/devops/services/k8s/deployment/deployment_common.go +++ /dev/null @@ -1,85 +0,0 @@ -package deployment - -import ( - apps "k8s.io/api/apps/v1" - v1 "k8s.io/api/core/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" - "pandax/apps/devops/services/k8s/event" -) - -// The code below allows to perform complex data section on Deployment - -type DeploymentCell apps.Deployment - -// GetProperty is used to get property of the deployment -func (self DeploymentCell) GetProperty(name dataselect.PropertyName) dataselect.ComparableValue { - switch name { - case dataselect.NameProperty: - return dataselect.StdComparableString(self.ObjectMeta.Name) - case dataselect.CreationTimestampProperty: - return dataselect.StdComparableTime(self.ObjectMeta.CreationTimestamp.Time) - case dataselect.NamespaceProperty: - return dataselect.StdComparableString(self.ObjectMeta.Namespace) - default: - // if name is not supported then just return a constant dummy value, sort will have no effect. - return nil - } -} - -func toCells(std []apps.Deployment) []dataselect.DataCell { - cells := make([]dataselect.DataCell, len(std)) - for i := range std { - cells[i] = DeploymentCell(std[i]) - } - return cells -} - -func fromCells(cells []dataselect.DataCell) []apps.Deployment { - std := make([]apps.Deployment, len(cells)) - for i := range std { - std[i] = apps.Deployment(cells[i].(DeploymentCell)) - } - return std -} - -func getStatus(list *apps.DeploymentList, rs []apps.ReplicaSet, pods []v1.Pod, events []v1.Event) k8scommon.ResourceStatus { - info := k8scommon.ResourceStatus{} - if list == nil { - return info - } - - for _, deployment := range list.Items { - matchingPods := k8scommon.FilterDeploymentPodsByOwnerReference(deployment, rs, pods) - podInfo := k8scommon.GetPodInfo(deployment.Status.Replicas, deployment.Spec.Replicas, matchingPods) - warnings := event.GetPodsEventWarnings(events, matchingPods) - - if len(warnings) > 0 { - info.Failed++ - } else if podInfo.Pending > 0 { - info.Pending++ - } else { - info.Running++ - } - } - - return info -} - -func getConditions(deploymentConditions []apps.DeploymentCondition) []k8scommon.Condition { - conditions := make([]k8scommon.Condition, 0) - - for _, condition := range deploymentConditions { - conditions = append(conditions, k8scommon.Condition{ - Type: string(condition.Type), - Status: metaV1.ConditionStatus(condition.Status), - Reason: condition.Reason, - Message: condition.Message, - LastTransitionTime: condition.LastTransitionTime, - LastProbeTime: condition.LastUpdateTime, - }) - } - - return conditions -} diff --git a/apps/devops/services/k8s/deployment/deployment_detail.go b/apps/devops/services/k8s/deployment/deployment_detail.go deleted file mode 100644 index ecf34c7..0000000 --- a/apps/devops/services/k8s/deployment/deployment_detail.go +++ /dev/null @@ -1,205 +0,0 @@ -package deployment - -import ( - "context" - "fmt" - "pandax/base/global" - "pandax/base/utils" - - apps "k8s.io/api/apps/v1" - v1 "k8s.io/api/core/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" - "k8s.io/client-go/kubernetes" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/event" - "pandax/apps/devops/services/k8s/service" - "sort" -) - -// RollingUpdateStrategy is behavior of a rolling update. See RollingUpdateDeployment K8s object. -type RollingUpdateStrategy struct { - MaxSurge *intstr.IntOrString `json:"maxSurge"` - MaxUnavailable *intstr.IntOrString `json:"maxUnavailable"` -} - -// StatusInfo is the status information of the deployment -type StatusInfo struct { - // Total number of desired replicas on the deployment - Replicas int32 `json:"replicas"` - - // Number of non-terminated pods that have the desired template spec - Updated int32 `json:"updated"` - - // Number of available pods (ready for at least minReadySeconds) - // targeted by this deployment - Available int32 `json:"available"` - - // Total number of unavailable pods targeted by this deployment. - Unavailable int32 `json:"unavailable"` -} - -// DeploymentDetail is a presentation layer view of Kubernetes Deployment resource. -type DeploymentDetail struct { - // Extends list item structure. - Deployment `json:",inline"` - - // Label selector of the service. - Selector map[string]string `json:"selector"` - - // Status information on the deployment - StatusInfo `json:"statusInfo"` - - // Conditions describe the state of a deployment at a certain point. - Conditions []k8scommon.Condition `json:"conditions"` - - // The deployment strategy to use to replace existing pods with new ones. - // Valid options: Recreate, RollingUpdate - Strategy apps.DeploymentStrategyType `json:"strategy"` - - // Min ready seconds - MinReadySeconds int32 `json:"minReadySeconds"` - - // Rolling update strategy containing maxSurge and maxUnavailable - RollingUpdateStrategy *RollingUpdateStrategy `json:"rollingUpdateStrategy,omitempty"` - - // Optional field that specifies the number of old Replica Sets to retain to allow rollback. - RevisionHistoryLimit *int32 `json:"revisionHistoryLimit"` - - // Events Info - Events []v1.Event `json:"events"` - - // Deployment history image version - HistoryVersion []HistoryVersion `json:"historyVersion"` - - PodList *PodList `json:"podList"` - - SvcList *service.ServiceList `json:"svcList"` -} - -// GetDeploymentDetail returns model object of deployment and error, if any. -func GetDeploymentDetail(client *kubernetes.Clientset, namespace string, deploymentName string) (*DeploymentDetail, error) { - - global.Log.Info(fmt.Sprintf("Getting details of %s deployment in %s namespace", deploymentName, namespace)) - - deployment, err := client.AppsV1().Deployments(namespace).Get(context.TODO(), deploymentName, metaV1.GetOptions{}) - if err != nil { - return nil, err - } - - selector, err := metaV1.LabelSelectorAsSelector(deployment.Spec.Selector) - if err != nil { - return nil, err - } - options := metaV1.ListOptions{LabelSelector: selector.String()} - - channels := &k8scommon.ResourceChannels{ - ReplicaSetList: k8scommon.GetReplicaSetListChannelWithOptions(client, - k8scommon.NewSameNamespaceQuery(namespace), options, 1), - PodList: k8scommon.GetPodListChannelWithOptions(client, - k8scommon.NewSameNamespaceQuery(namespace), options, 1), - EventList: k8scommon.GetEventListChannelWithOptions(client, - k8scommon.NewSameNamespaceQuery(namespace), options, 1), - } - - rawRs := <-channels.ReplicaSetList.List - err = <-channels.ReplicaSetList.Error - if err != nil { - return nil, err - } - - rawPods := <-channels.PodList.List - err = <-channels.PodList.Error - if err != nil { - return nil, err - } - - rawEvents := <-channels.EventList.List - err = <-channels.EventList.Error - if err != nil { - return nil, err - } - - // Extra Info - var rollingUpdateStrategy *RollingUpdateStrategy - if deployment.Spec.Strategy.RollingUpdate != nil { - rollingUpdateStrategy = &RollingUpdateStrategy{ - MaxSurge: deployment.Spec.Strategy.RollingUpdate.MaxSurge, - MaxUnavailable: deployment.Spec.Strategy.RollingUpdate.MaxUnavailable, - } - } - events, _ := event.GetEvents(client, namespace, fmt.Sprintf("involvedObject.name=%v", deploymentName)) - serviceList, _ := service.GetToService(client, namespace, deploymentName) - - return &DeploymentDetail{ - Deployment: toDeployment(deployment, rawRs.Items, rawPods.Items, rawEvents.Items), - Selector: deployment.Spec.Selector.MatchLabels, - StatusInfo: GetStatusInfo(&deployment.Status), - Conditions: getConditions(deployment.Status.Conditions), - Strategy: deployment.Spec.Strategy.Type, - MinReadySeconds: deployment.Spec.MinReadySeconds, - RollingUpdateStrategy: rollingUpdateStrategy, - RevisionHistoryLimit: deployment.Spec.RevisionHistoryLimit, - Events: events, - PodList: getDeploymentToPod(client, deployment), - SvcList: serviceList, - HistoryVersion: getDeploymentHistory(namespace, deploymentName, rawRs.Items), - }, nil -} - -// GetStatusInfo is used to get the status information from the *apps.DeploymentStatus -func GetStatusInfo(deploymentStatus *apps.DeploymentStatus) StatusInfo { - return StatusInfo{ - Replicas: deploymentStatus.Replicas, - Updated: deploymentStatus.UpdatedReplicas, - Available: deploymentStatus.AvailableReplicas, - Unavailable: deploymentStatus.UnavailableReplicas, - } -} - -type HistoryVersion struct { - CreateTime metaV1.Time `json:"create_time"` - Image string `json:"image"` - Version int64 `json:"version"` - Namespace string `json:"namespace"` - Name string `json:"name"` -} - -func getDeploymentHistory(namespace string, deploymentName string, rs []apps.ReplicaSet) []HistoryVersion { - - var historyVersion []HistoryVersion - - for _, v := range rs { - if namespace == v.Namespace && deploymentName == v.OwnerReferences[0].Name { - history := HistoryVersion{ - CreateTime: v.CreationTimestamp, - Image: v.Spec.Template.Spec.Containers[0].Image, - Version: utils.ParseStringToInt64(v.Annotations["deployment.kubernetes.io/revision"]), - Namespace: v.Namespace, - Name: v.OwnerReferences[0].Name, - } - historyVersion = append(historyVersion, history) - - } - } - // Sort the map by date - //sort.Slice(historyVersion, func(i, j int) bool { - // return historyVersion[j].CreateTime.Before(&historyVersion[i].CreateTime) - //}) - // Sort the map by version - sort.Sort(historiesByRevision(historyVersion)) - - return historyVersion -} - -type historiesByRevision []HistoryVersion - -func (h historiesByRevision) Len() int { - return len(h) -} -func (h historiesByRevision) Swap(i, j int) { - h[i], h[j] = h[j], h[i] -} -func (h historiesByRevision) Less(i, j int) bool { - return h[j].Version < h[i].Version -} diff --git a/apps/devops/services/k8s/deployment/deployment_pod_test.go b/apps/devops/services/k8s/deployment/deployment_pod_test.go deleted file mode 100644 index e648c8f..0000000 --- a/apps/devops/services/k8s/deployment/deployment_pod_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package deployment - -import ( - "context" - "fmt" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/clientcmd" - clientcmdapi "k8s.io/client-go/tools/clientcmd/api" - "log" - "testing" -) - -func TestGetDeploymentToPod(t *testing.T) { - rules := clientcmd.NewDefaultClientConfigLoadingRules() - overrides := &clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{InsecureSkipTLSVerify: true}} - config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(rules, overrides).ClientConfig() - if err != nil { - log.Fatalf("Couldn't get Kubernetes default config: %s", err) - } - - client, err := kubernetes.NewForConfig(config) - if err != nil { - log.Fatalln(err) - } - namespace := "default" - name := "nginx" - selector := getDeployment(client, namespace, name) - pod, err := getPod(client, namespace, selector) - if err != nil { - log.Fatalln(err) - } - fmt.Printf("podList: %v\n", pod) - -} - -func getDeployment(client *kubernetes.Clientset, namespace, name string) (selector labels.Selector) { - fmt.Println("开始获取deployment") - deployment, err := client.AppsV1().Deployments(namespace).Get(context.TODO(), name, metav1.GetOptions{}) - if err != nil { - fmt.Println(err) - } - - selector, _ = metav1.LabelSelectorAsSelector(deployment.Spec.Selector) - - return selector -} - -func getPod(client *kubernetes.Clientset, namespace string, selector labels.Selector) (*v1.PodList, error) { - fmt.Println("根据deployment过滤pod") - pod, err := client.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{ - LabelSelector: selector.String(), - }) - if err != nil { - return nil, err - } - - return pod, nil -} diff --git a/apps/devops/services/k8s/deployment/deployment_pods.go b/apps/devops/services/k8s/deployment/deployment_pods.go deleted file mode 100644 index e53fbf6..0000000 --- a/apps/devops/services/k8s/deployment/deployment_pods.go +++ /dev/null @@ -1,50 +0,0 @@ -package deployment - -import ( - "context" - "pandax/base/global" - - "go.uber.org/zap" - apps "k8s.io/api/apps/v1" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/event" - "pandax/apps/devops/services/k8s/pods" -) - -type PodList struct { - ListMeta k8s.ListMeta `json:"listMeta"` - - // Basic information about resources status on the list. - Status k8scommon.ResourceStatus `json:"status"` - - // Unordered list of Pods. - Pods []pods.Pod `json:"pods"` -} - -func getDeploymentToPod(client *kubernetes.Clientset, deployment *apps.Deployment) (po *PodList) { - - selector, err := metav1.LabelSelectorAsSelector(deployment.Spec.Selector) - if err != nil { - return nil - } - options := metav1.ListOptions{LabelSelector: selector.String()} - - podData, err := client.CoreV1().Pods(deployment.Namespace).List(context.TODO(), options) - if err != nil { - global.Log.Error("Get a pod exception from the deployment", zap.Any("err", err)) - } - podList := PodList{ - Pods: make([]pods.Pod, 0), - } - podList.ListMeta = k8s.ListMeta{TotalItems: len(podData.Items)} - for _, pod := range podData.Items { - warnings := event.GetPodsEventWarnings(nil, []v1.Pod{pod}) - podDetail := pods.ToPod(&pod, warnings) - podList.Pods = append(podList.Pods, podDetail) - } - return &podList -} diff --git a/apps/devops/services/k8s/deployment/deployment_svc_test.go b/apps/devops/services/k8s/deployment/deployment_svc_test.go deleted file mode 100644 index 1318f22..0000000 --- a/apps/devops/services/k8s/deployment/deployment_svc_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package deployment - -import ( - "context" - "encoding/json" - "fmt" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/clientcmd" - clientcmdapi "k8s.io/client-go/tools/clientcmd/api" - "log" - "os" - "strings" - "testing" -) - -func TestGetDeploymentToSVC(t *testing.T) { - rules := clientcmd.NewDefaultClientConfigLoadingRules() - overrides := &clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{InsecureSkipTLSVerify: true}} - config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(rules, overrides).ClientConfig() - if err != nil { - log.Fatalf("Couldn't get Kubernetes default config: %s", err) - } - - client, err := kubernetes.NewForConfig(config) - if err != nil { - log.Fatalln(err) - } - namespace := "develop" - name := "service" - //selector := getDeployment(client, namespace, name) - svcData, err := getSvc(client, namespace, name) - if err != nil { - log.Fatalln(err) - } - svcJSON, _ := json.Marshal(svcData) - fmt.Printf("svcList: %s\n", svcJSON) - -} - -func getSvc(client *kubernetes.Clientset, namespace string, name string) (svc *v1.Service, err error) { - svcList, err := client.CoreV1().Services(namespace).List(context.TODO(), metav1.ListOptions{}) - fmt.Printf("开始获取svc: %v\n", svcList) - if err != nil { - fmt.Println(err) - return nil, err - } - for _, svc := range svcList.Items { - if strings.Contains(svc.Name, name) { - fmt.Fprintf(os.Stdout, "service name: %v\n", svc.Name) - return &svc, nil - } - } - return svc, nil - -} diff --git a/apps/devops/services/k8s/endpoint/endpoint.go b/apps/devops/services/k8s/endpoint/endpoint.go deleted file mode 100644 index c7e52cf..0000000 --- a/apps/devops/services/k8s/endpoint/endpoint.go +++ /dev/null @@ -1,85 +0,0 @@ -package endpoint - -import ( - "fmt" - "pandax/base/global" - - v1 "k8s.io/api/core/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/labels" - k8sClient "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" -) - -type Endpoint struct { - ObjectMeta k8s.ObjectMeta `json:"objectMeta"` - TypeMeta k8s.TypeMeta `json:"typeMeta"` - - // Hostname, either as a domain name or IP address. - Host string `json:"host"` - - // Name of the node the endpoint is located - NodeName *string `json:"nodeName"` - - // Status of the endpoint - Ready bool `json:"ready"` - - // Array of endpoint ports - Ports []v1.EndpointPort `json:"ports"` -} - -// GetServiceEndpoints gets list of endpoints targeted by given label selector in given namespace. -func GetServiceEndpoints(client k8sClient.Interface, namespace, name string) (*EndpointList, error) { - endpointList := &EndpointList{ - Endpoints: make([]Endpoint, 0), - ListMeta: k8s.ListMeta{TotalItems: 0}, - } - - serviceEndpoints, err := GetEndpoints(client, namespace, name) - if err != nil { - return endpointList, err - } - - endpointList = toEndpointList(serviceEndpoints) - global.Log.Info(fmt.Sprintf("Found %d endpoints related to %s service in %s namespace", len(endpointList.Endpoints), name, namespace)) - return endpointList, nil -} - -// GetEndpoints gets endpoints associated to resource with given name. -func GetEndpoints(client k8sClient.Interface, namespace, name string) ([]v1.Endpoints, error) { - fieldSelector, err := fields.ParseSelector("metadata.name" + "=" + name) - if err != nil { - return nil, err - } - - channels := &k8scommon.ResourceChannels{ - EndpointList: k8scommon.GetEndpointListChannelWithOptions(client, - k8scommon.NewSameNamespaceQuery(namespace), - metaV1.ListOptions{ - LabelSelector: labels.Everything().String(), - FieldSelector: fieldSelector.String(), - }, - 1), - } - - endpointList := <-channels.EndpointList.List - if err := <-channels.EndpointList.Error; err != nil { - return nil, err - } - - return endpointList.Items, nil -} - -// toEndpoint converts endpoint api Endpoint to Endpoint model object. -func toEndpoint(address v1.EndpointAddress, ports []v1.EndpointPort, ready bool) *Endpoint { - - return &Endpoint{ - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindEndpoint), - Host: address.IP, - Ports: ports, - Ready: ready, - NodeName: address.NodeName, - } -} diff --git a/apps/devops/services/k8s/endpoint/list.go b/apps/devops/services/k8s/endpoint/list.go deleted file mode 100644 index 9c9309e..0000000 --- a/apps/devops/services/k8s/endpoint/list.go +++ /dev/null @@ -1,33 +0,0 @@ -package endpoint - -import ( - v1 "k8s.io/api/core/v1" - "pandax/apps/devops/entity/k8s" -) - -type EndpointList struct { - ListMeta k8s.ListMeta `json:"listMeta"` - // List of endpoints - Endpoints []Endpoint `json:"endpoints"` -} - -// toEndpointList converts array of api events to endpoint List structure -func toEndpointList(endpoints []v1.Endpoints) *EndpointList { - endpointList := EndpointList{ - Endpoints: make([]Endpoint, 0), - ListMeta: k8s.ListMeta{TotalItems: len(endpoints)}, - } - - for _, endpoint := range endpoints { - for _, subSets := range endpoint.Subsets { - for _, address := range subSets.Addresses { - endpointList.Endpoints = append(endpointList.Endpoints, *toEndpoint(address, subSets.Ports, true)) - } - for _, notReadyAddress := range subSets.NotReadyAddresses { - endpointList.Endpoints = append(endpointList.Endpoints, *toEndpoint(notReadyAddress, subSets.Ports, false)) - } - } - } - - return &endpointList -} diff --git a/apps/devops/services/k8s/event/event_common.go b/apps/devops/services/k8s/event/event_common.go deleted file mode 100644 index b43d91a..0000000 --- a/apps/devops/services/k8s/event/event_common.go +++ /dev/null @@ -1,237 +0,0 @@ -package event - -import ( - "context" - "fmt" - v1 "k8s.io/api/core/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" -) - -// EmptyEventList is a empty list of events. -var EmptyEventList = &k8scommon.EventList{ - Events: make([]k8scommon.Event, 0), - ListMeta: k8s.ListMeta{ - TotalItems: 0, - }, -} - -// ToEvent converts event api Event to Event model object. -func ToEvent(event v1.Event) k8scommon.Event { - result := k8scommon.Event{ - ObjectMeta: k8s.NewObjectMeta(event.ObjectMeta), - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindEvent), - Message: event.Message, - SourceComponent: event.Source.Component, - SourceHost: event.Source.Host, - SubObject: event.InvolvedObject.FieldPath, - SubObjectKind: event.InvolvedObject.Kind, - SubObjectName: event.InvolvedObject.Name, - SubObjectNamespace: event.InvolvedObject.Namespace, - Count: event.Count, - FirstSeen: event.FirstTimestamp, - LastSeen: event.LastTimestamp, - Reason: event.Reason, - Type: event.Type, - } - - return result -} - -// FailedReasonPartials is an array of partial strings to correctly filter warning events. -// Have to be lower case for correct case insensitive comparison. -// Based on k8s official events reason file: -// https://github.com/kubernetes/kubernetes/blob/886e04f1fffbb04faf8a9f9ee141143b2684ae68/pkg/kubelet/events/event.go -// Partial strings that are not in event.go file are added in order to support -// older versions of k8s which contained additional event reason messages. -var FailedReasonPartials = []string{"failed", "err", "exceeded", "invalid", "unhealthy", - "mismatch", "insufficient", "conflict", "outof", "nil", "backoff"} - -// GetNodeEvents gets events associated to node with given name. -func GetNodeEvents(client *kubernetes.Clientset, nodeName string) (*v1.EventList, error) { - - //scheme := runtime.NewScheme() - //groupVersion := schema.GroupVersion{Group: "", Version: "v1"} - //scheme.AddKnownTypes(groupVersion, &v1.Node{}) - // - //node, err := client.CoreV1().Nodes().Get(context.TODO(), nodeName, metaV1.GetOptions{}) - // - //if err != nil { - // return nil, err - //} - events, err := client.CoreV1().Events(v1.NamespaceAll).List(context.TODO(), - metaV1.ListOptions{FieldSelector: fmt.Sprintf("involvedObject.name=%v", nodeName)}) - - //events, err := client.CoreV1().Events(v1.NamespaceAll).Search(scheme, node) - - if err != nil { - return nil, err - } - - return events, nil -} - -// FillEventsType is based on event Reason fills event Type in order to allow correct filtering by Type. -func FillEventsType(events []v1.Event) []v1.Event { - for i := range events { - // Fill in only events with empty type. - if len(events[i].Type) == 0 { - if isFailedReason(events[i].Reason, FailedReasonPartials...) { - events[i].Type = v1.EventTypeWarning - } else { - events[i].Type = v1.EventTypeNormal - } - } - } - - return events -} - -// GetResourceEvents gets events associated to specified resource. -func GetResourceEvents(client *kubernetes.Clientset, dsQuery *dataselect.DataSelectQuery, namespace, name string) (*k8scommon.EventList, error) { - resourceEvents, err := GetEvents(client, namespace, name) - - if err != nil { - return EmptyEventList, err - } - - events := CreateEventList(resourceEvents, dsQuery) - return &events, nil -} - -// CreateEventList converts array of api events to common EventList structure -func CreateEventList(events []v1.Event, dsQuery *dataselect.DataSelectQuery) k8scommon.EventList { - eventList := k8scommon.EventList{ - Events: make([]k8scommon.Event, 0), - ListMeta: k8s.ListMeta{TotalItems: len(events)}, - } - - events = fromCells(dataselect.GenericDataSelect(toCells(events), dsQuery)) - for _, event := range events { - eventDetail := ToEvent(event) - eventList.Events = append(eventList.Events, eventDetail) - } - - return eventList -} - -// The code below allows to perform complex data section on []api.Event - -type EventCell v1.Event - -func (self EventCell) GetProperty(name dataselect.PropertyName) dataselect.ComparableValue { - switch name { - case dataselect.NameProperty: - return dataselect.StdComparableString(self.ObjectMeta.Name) - case dataselect.CreationTimestampProperty: - return dataselect.StdComparableTime(self.ObjectMeta.CreationTimestamp.Time) - case dataselect.FirstSeenProperty: - return dataselect.StdComparableTime(self.FirstTimestamp.Time) - case dataselect.LastSeenProperty: - return dataselect.StdComparableTime(self.LastTimestamp.Time) - case dataselect.NamespaceProperty: - return dataselect.StdComparableString(self.ObjectMeta.Namespace) - case dataselect.ReasonProperty: - return dataselect.StdComparableString(self.Reason) - default: - // if name is not supported then just return a constant dummy value, sort will have no effect. - return nil - } -} - -func toCells(std []v1.Event) []dataselect.DataCell { - cells := make([]dataselect.DataCell, len(std)) - for i := range std { - cells[i] = EventCell(std[i]) - } - return cells -} - -func fromCells(cells []dataselect.DataCell) []v1.Event { - std := make([]v1.Event, len(cells)) - for i := range std { - std[i] = v1.Event(cells[i].(EventCell)) - } - return std -} - -// GetEvents gets events associated to resource with given name. -func GetEvents(client *kubernetes.Clientset, namespace, resourceName string) ([]v1.Event, error) { - fieldSelector, err := fields.ParseSelector("involvedObject.name" + "=" + resourceName) - - if err != nil { - return nil, err - } - - channels := &k8scommon.ResourceChannels{ - EventList: k8scommon.GetEventListChannelWithOptions(client, k8scommon.NewSameNamespaceQuery(namespace), - metaV1.ListOptions{ - LabelSelector: labels.Everything().String(), - FieldSelector: fieldSelector.String(), - }, - 1), - } - - eventList := <-channels.EventList.List - if err := <-channels.EventList.Error; err != nil { - return nil, err - } - - return FillEventsType(eventList.Items), nil -} - -// GetPodEvents gets pods events associated to pod name and namespace -func GetPodEvents(client *kubernetes.Clientset, namespace, podName string) ([]v1.Event, error) { - - channels := &k8scommon.ResourceChannels{ - PodList: k8scommon.GetPodListChannel(client, k8scommon.NewSameNamespaceQuery(namespace), 1), - EventList: k8scommon.GetEventListChannel(client, k8scommon.NewSameNamespaceQuery(namespace), 1), - } - - podList := <-channels.PodList.List - if err := <-channels.PodList.Error; err != nil { - return nil, err - } - - eventList := <-channels.EventList.List - if err := <-channels.EventList.Error; err != nil { - return nil, err - } - - l := make([]v1.Pod, 0) - for _, pi := range podList.Items { - if pi.Name == podName { - l = append(l, pi) - } - } - - events := filterEventsByPodsUID(eventList.Items, l) - return FillEventsType(events), nil -} - -// GetPodsEvents gets events targeting given list of pods. -func GetPodsEvents(client *kubernetes.Clientset, namespace string, pods []v1.Pod) ([]v1.Event, error) { - - nsQuery := k8scommon.NewSameNamespaceQuery(namespace) - if namespace == v1.NamespaceAll { - nsQuery = k8scommon.NewNamespaceQuery([]string{}) - } - - channels := &k8scommon.ResourceChannels{ - EventList: k8scommon.GetEventListChannel(client, nsQuery, 1), - } - - eventList := <-channels.EventList.List - if err := <-channels.EventList.Error; err != nil { - return nil, err - } - - events := filterEventsByPodsUID(eventList.Items, pods) - - return events, nil -} diff --git a/apps/devops/services/k8s/event/events.go b/apps/devops/services/k8s/event/events.go deleted file mode 100644 index d51eafb..0000000 --- a/apps/devops/services/k8s/event/events.go +++ /dev/null @@ -1,147 +0,0 @@ -package event - -import ( - "context" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/services/k8s/common" - "strings" -) - -func GetClusterNodeEvent(client *kubernetes.Clientset, namespace string, field string) (*v1.EventList, error) { - - events, err := client.CoreV1().Events(namespace).List(context.TODO(), - metav1.ListOptions{ - FieldSelector: field, - }, - ) - if err != nil { - return nil, err - } - return events, nil -} - -// GetPodsEventWarnings returns warning pod events by filtering out events targeting only given pods -func GetPodsEventWarnings(events []v1.Event, pods []v1.Pod) []common.Event { - result := make([]common.Event, 0) - - // Filter out only warning events - events = getWarningEvents(events) - failedPods := make([]v1.Pod, 0) - - // Filter out ready and successful pods - for _, pod := range pods { - if !isReadyOrSucceeded(pod) { - failedPods = append(failedPods, pod) - } - } - - // Filter events by failed pods UID - events = filterEventsByPodsUID(events, failedPods) - events = removeDuplicates(events) - - for _, event := range events { - result = append(result, common.Event{ - Message: event.Message, - Reason: event.Reason, - Type: event.Type, - }) - } - - return result -} - -// Returns filtered list of event objects. -// Event list object is filtered to get only warning events. -func getWarningEvents(events []v1.Event) []v1.Event { - return filterEventsByType(FillEventsType(events), v1.EventTypeWarning) -} - -// Returns true if given pod is in state ready or succeeded, false otherwise -func isReadyOrSucceeded(pod v1.Pod) bool { - if pod.Status.Phase == v1.PodSucceeded { - return true - } - if pod.Status.Phase == v1.PodRunning { - for _, c := range pod.Status.Conditions { - if c.Type == v1.PodReady { - if c.Status == v1.ConditionFalse { - return false - } - } - } - - return true - } - - return false -} - -// Returns filtered list of event objects. Events list is filtered to get only events targeting -// pods on the list. -func filterEventsByPodsUID(events []v1.Event, pods []v1.Pod) []v1.Event { - result := make([]v1.Event, 0) - podEventMap := make(map[types.UID]bool, 0) - - if len(pods) == 0 || len(events) == 0 { - return result - } - - for _, pod := range pods { - podEventMap[pod.UID] = true - } - - for _, event := range events { - if _, exists := podEventMap[event.InvolvedObject.UID]; exists { - result = append(result, event) - } - } - - return result -} - -// Removes duplicate strings from the slice -func removeDuplicates(slice []v1.Event) []v1.Event { - visited := make(map[string]bool, 0) - result := make([]v1.Event, 0) - - for _, elem := range slice { - if !visited[elem.Reason] { - visited[elem.Reason] = true - result = append(result, elem) - } - } - - return result -} - -// Filters kubernetes API event objects based on event type. -// Empty string will return all events. -func filterEventsByType(events []v1.Event, eventType string) []v1.Event { - if len(eventType) == 0 || len(events) == 0 { - return events - } - - result := make([]v1.Event, 0) - for _, event := range events { - if event.Type == eventType { - result = append(result, event) - } - } - - return result -} - -// Returns true if reason string contains any partial string indicating that this may be a -// warning, false otherwise -func isFailedReason(reason string, partials ...string) bool { - for _, partial := range partials { - if strings.Contains(strings.ToLower(reason), partial) { - return true - } - } - - return false -} diff --git a/apps/devops/services/k8s/evict/evict.go b/apps/devops/services/k8s/evict/evict.go deleted file mode 100644 index 8ca1512..0000000 --- a/apps/devops/services/k8s/evict/evict.go +++ /dev/null @@ -1,58 +0,0 @@ -package evict - -import ( - "context" - "fmt" - "pandax/base/global" - - policy "k8s.io/api/policy/v1beta1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" -) - -var ( - systemNamespace = "kube-system" -) - -func EvictsNodePods(client *kubernetes.Clientset, nodeName string) error { - /* - 驱逐节点上不在 kube-system 命名空间中的所有 pod - */ - pods, err := client.CoreV1().Pods("").List(context.TODO(), metav1.ListOptions{ - FieldSelector: "spec.nodeName=" + nodeName, - }) - - if err != nil { - return err - } - for _, i := range pods.Items { - if i.Namespace == systemNamespace { - continue - } else { - global.Log.Info(fmt.Sprintf("开始驱逐Node: %v, 节点Namespace: %v下的Pod: %v", nodeName, i.Namespace, i.Name)) - err := EvictsPod(client, i.Name, i.Namespace) - if err != nil { - global.Log.Error(fmt.Sprintf("驱逐Pod:%v失败", i.Name)) - } - } - } - global.Log.Info(fmt.Sprintf("已成功从节点: %v 中驱逐所有pod", nodeName)) - return nil -} - -func EvictsPod(client *kubernetes.Clientset, name, namespace string) error { - // Pod优雅退出时间, 默认退出时间30s, 如果未指定, 则默认为每个对象的值。0表示立即删除。 - var gracePeriodSeconds int64 = 0 - propagationPolicy := metav1.DeletePropagationForeground - deleteOptions := &metav1.DeleteOptions{ - GracePeriodSeconds: &gracePeriodSeconds, - PropagationPolicy: &propagationPolicy, - } - return client.PolicyV1beta1().Evictions(namespace).Evict(context.TODO(), &policy.Eviction{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - DeleteOptions: deleteOptions, - }) -} diff --git a/apps/devops/services/k8s/ingress/ingress.go b/apps/devops/services/k8s/ingress/ingress.go deleted file mode 100644 index 5c5ac2f..0000000 --- a/apps/devops/services/k8s/ingress/ingress.go +++ /dev/null @@ -1,133 +0,0 @@ -package ingress - -import ( - "context" - "fmt" - "pandax/base/global" - - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" - //v1 "k8s.io/api/extensions/v1beta1" - v1 "k8s.io/api/networking/v1beta1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - client "k8s.io/client-go/kubernetes" -) - -// Ingress - a single ingress returned to the frontend. -type Ingress struct { - k8s.ObjectMeta `json:"objectMeta"` - k8s.TypeMeta `json:"typeMeta"` - - // External endpoints of this ingress. - Endpoints []k8scommon.Endpoint `json:"endpoints"` - Hosts []string `json:"hosts"` - Spec v1.IngressSpec `json:"spec"` - Status v1.IngressStatus `json:"status"` -} - -// IngressList - response structure for a queried ingress list. -type IngressList struct { - k8s.ListMeta `json:"listMeta"` - - // Unordered list of Ingresss. - Items []Ingress `json:"items"` -} - -// GetIngressList returns all ingresses in the given namespace. -func GetIngressList(client *client.Clientset, namespace *k8scommon.NamespaceQuery, dsQuery *dataselect.DataSelectQuery) (*IngressList, error) { - //ingressList, err := client.ExtensionsV1beta1().Ingresses(namespace.ToRequestParam()).List(context.TODO(), k8s.ListEverything) - ingressList, err := client.NetworkingV1beta1().Ingresses(namespace.ToRequestParam()).List(context.TODO(), k8s.ListEverything) - - if err != nil { - return nil, err - } - return toIngressList(ingressList.Items, dsQuery), nil - -} - -func getEndpoints(ingress *v1.Ingress) []k8scommon.Endpoint { - endpoints := make([]k8scommon.Endpoint, 0) - if len(ingress.Status.LoadBalancer.Ingress) > 0 { - for _, status := range ingress.Status.LoadBalancer.Ingress { - endpoint := k8scommon.Endpoint{} - if status.Hostname != "" { - endpoint.Host = status.Hostname - } else if status.IP != "" { - endpoint.Host = status.IP - } - endpoints = append(endpoints, endpoint) - } - } - return endpoints -} - -func getHosts(ingress *v1.Ingress) []string { - hosts := make([]string, 0) - set := make(map[string]struct{}) - - for _, rule := range ingress.Spec.Rules { - if _, exists := set[rule.Host]; !exists && len(rule.Host) > 0 { - hosts = append(hosts, rule.Host) - } - - set[rule.Host] = struct{}{} - } - - return hosts -} - -func toIngress(ingress *v1.Ingress) Ingress { - return Ingress{ - ObjectMeta: k8s.NewObjectMeta(ingress.ObjectMeta), - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindIngress), - Endpoints: getEndpoints(ingress), - Hosts: getHosts(ingress), - Spec: ingress.Spec, - Status: ingress.Status, - } -} - -func toIngressList(ingresses []v1.Ingress, dsQuery *dataselect.DataSelectQuery) *IngressList { - newIngressList := &IngressList{ - ListMeta: k8s.ListMeta{TotalItems: len(ingresses)}, - Items: make([]Ingress, 0), - } - - ingresCells, filteredTotal := dataselect.GenericDataSelectWithFilter(toCells(ingresses), dsQuery) - ingresses = fromCells(ingresCells) - newIngressList.ListMeta = k8s.ListMeta{TotalItems: filteredTotal} - - for _, ingress := range ingresses { - newIngressList.Items = append(newIngressList.Items, toIngress(&ingress)) - } - - return newIngressList -} - -func DeleteIngress(client *client.Clientset, namespace string, name string) error { - global.Log.Info(fmt.Sprintf("请求删除Ingress: %v, namespace: %v", name, namespace)) - return client.ExtensionsV1beta1().Ingresses(namespace).Delete( - context.TODO(), - name, - metav1.DeleteOptions{}, - ) -} - -func DeleteCollectionIngress(client *client.Clientset, ingressList []k8s.ServiceData) (err error) { - global.Log.Info("批量删除Ingress开始") - for _, v := range ingressList { - global.Log.Info(fmt.Sprintf("delete ingress:%v, ns: %v", v.Name, v.Namespace)) - err := client.ExtensionsV1beta1().Ingresses(v.Namespace).Delete( - context.TODO(), - v.Name, - metav1.DeleteOptions{}, - ) - if err != nil { - global.Log.Error(err.Error()) - return err - } - } - global.Log.Info("删除ingress已完成") - return nil -} diff --git a/apps/devops/services/k8s/ingress/ingress_common.go b/apps/devops/services/k8s/ingress/ingress_common.go deleted file mode 100644 index b39fb71..0000000 --- a/apps/devops/services/k8s/ingress/ingress_common.go +++ /dev/null @@ -1,41 +0,0 @@ -package ingress - -import ( - "pandax/apps/devops/services/k8s/dataselect" - //v1 "k8s.io/api/extensions/v1beta1" - v1 "k8s.io/api/networking/v1beta1" -) - -// The code below allows to perform complex data section on []extensions.Ingress - -type IngressCell v1.Ingress - -func (self IngressCell) GetProperty(name dataselect.PropertyName) dataselect.ComparableValue { - switch name { - case dataselect.NameProperty: - return dataselect.StdComparableString(self.ObjectMeta.Name) - case dataselect.CreationTimestampProperty: - return dataselect.StdComparableTime(self.ObjectMeta.CreationTimestamp.Time) - case dataselect.NamespaceProperty: - return dataselect.StdComparableString(self.ObjectMeta.Namespace) - default: - // if name is not supported then just return a constant dummy value, sort will have no effect. - return nil - } -} - -func toCells(std []v1.Ingress) []dataselect.DataCell { - cells := make([]dataselect.DataCell, len(std)) - for i := range std { - cells[i] = IngressCell(std[i]) - } - return cells -} - -func fromCells(cells []dataselect.DataCell) []v1.Ingress { - std := make([]v1.Ingress, len(cells)) - for i := range std { - std[i] = v1.Ingress(cells[i].(IngressCell)) - } - return std -} diff --git a/apps/devops/services/k8s/ingress/ingress_detail.go b/apps/devops/services/k8s/ingress/ingress_detail.go deleted file mode 100644 index ef32aad..0000000 --- a/apps/devops/services/k8s/ingress/ingress_detail.go +++ /dev/null @@ -1,46 +0,0 @@ -package ingress - -import ( - "context" - "fmt" - "pandax/base/global" - - //v1 "k8s.io/api/extensions/v1beta1" - v1 "k8s.io/api/networking/v1beta1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - client "k8s.io/client-go/kubernetes" -) - -// IngressDetail API resource provides mechanisms to inject containers with configuration data while keeping -// containers agnostic of Kubernetes -type IngressDetail struct { - // Extends list item structure. - Ingress `json:",inline"` - - // Spec is the desired state of the Ingress. - Spec v1.IngressSpec `json:"spec"` - - // Status is the current state of the Ingress. - Status v1.IngressStatus `json:"status"` -} - -// GetIngressDetail returns detailed information about an ingress -func GetIngressDetail(client *client.Clientset, namespace, name string) (*IngressDetail, error) { - global.Log.Info(fmt.Sprintf("Getting details of %s ingress in %s namespace", name, namespace)) - - //rawIngress, err := client.ExtensionsV1beta1().Ingresses(namespace).Get(context.TODO(), name, metaV1.GetOptions{}) - rawIngress, err := client.NetworkingV1beta1().Ingresses(namespace).Get(context.TODO(), name, metaV1.GetOptions{}) - if err != nil { - return nil, err - } - - return getIngressDetail(rawIngress), nil -} - -func getIngressDetail(i *v1.Ingress) *IngressDetail { - return &IngressDetail{ - Ingress: toIngress(i), - Spec: i.Spec, - Status: i.Status, - } -} diff --git a/apps/devops/services/k8s/ingress/ingress_test.go b/apps/devops/services/k8s/ingress/ingress_test.go deleted file mode 100644 index 12a3c6d..0000000 --- a/apps/devops/services/k8s/ingress/ingress_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package ingress - -import ( - "context" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/clientcmd" - clientcmdapi "k8s.io/client-go/tools/clientcmd/api" - "log" - "testing" -) - -func TestGetIngressList(t *testing.T) { - - rules := clientcmd.NewDefaultClientConfigLoadingRules() - overrides := &clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{InsecureSkipTLSVerify: true}} - config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(rules, overrides).ClientConfig() - if err != nil { - log.Fatalf("Couldn't get Kubernetes default config: %s", err) - } - - client, err := kubernetes.NewForConfig(config) - if err != nil { - log.Fatalln(err) - } - - ingressList, err := client.ExtensionsV1beta1().Ingresses("").List(context.TODO(), metav1.ListOptions{}) - - log.Print(ingressList) - -} diff --git a/apps/devops/services/k8s/job/job.go b/apps/devops/services/k8s/job/job.go deleted file mode 100644 index 2ab1a83..0000000 --- a/apps/devops/services/k8s/job/job.go +++ /dev/null @@ -1,253 +0,0 @@ -package job - -import ( - "context" - "fmt" - "pandax/base/global" - - batch "k8s.io/api/batch/v1" - v1 "k8s.io/api/core/v1" - meta "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" - "pandax/apps/devops/services/k8s/event" -) - -// JobList contains a list of Jobs in the cluster. -type JobList struct { - ListMeta k8s.ListMeta `json:"listMeta"` - - // Basic information about resources status on the list. - Status k8scommon.ResourceStatus `json:"status"` - - // Unordered list of Jobs. - Jobs []Job `json:"jobs"` - - // List of non-critical errors, that occurred during resource retrieval. - Errors []error `json:"errors"` -} - -type JobStatusType string - -const ( - // JobStatusRunning means the job is still running. - JobStatusRunning JobStatusType = "Running" - // JobStatusComplete means the job has completed its execution. - JobStatusComplete JobStatusType = "Complete" - // JobStatusFailed means the job has failed its execution. - JobStatusFailed JobStatusType = "Failed" -) - -type JobStatus struct { - // Short, machine understandable job status code. - Status JobStatusType `json:"status"` - // A human-readable description of the status of related job. - Message string `json:"message"` - // Conditions describe the state of a job after it finishes. - Conditions []k8scommon.Condition `json:"conditions"` -} - -// Job is a presentation layer view of Kubernetes Job resource. This means it is Job plus additional -// augmented data we can get from other sources -type Job struct { - ObjectMeta k8s.ObjectMeta `json:"objectMeta"` - TypeMeta k8s.TypeMeta `json:"typeMeta"` - - // Aggregate information about pods belonging to this Job. - Pods k8scommon.PodInfo `json:"podInfo"` - - // Container images of the Job. - ContainerImages []string `json:"containerImages"` - - // Init Container images of the Job. - InitContainerImages []string `json:"initContainerImages"` - - // number of parallel jobs defined. - Parallelism *int32 `json:"parallelism"` - - // JobStatus contains inferred job status based on job conditions - JobStatus JobStatus `json:"jobStatus"` - - PodStatus PodStatus `json:"podStatus"` -} - -type PodStatus struct { - // Represents time when the job controller started processing a job. When a - // Job is created in the suspended state, this field is not set until the - // first time it is resumed. This field is reset every time a Job is resumed - // from suspension. It is represented in RFC3339 form and is in UTC. - // +optional - StartTime *meta.Time `json:"startTime"` - - // Represents time when the job was completed. It is not guaranteed to - // be set in happens-before order across separate operations. - // It is represented in RFC3339 form and is in UTC. - // The completion time is only set when the job finishes successfully. - // +optional - CompletionTime *meta.Time `json:"completionTime"` - - // The number of actively running pods. - // +optional - Active int32 `json:"active"` - - // The number of pods which reached phase Succeeded. - // +optional - Succeeded int32 `json:"succeeded"` - - // The number of pods which reached phase Failed. - // +optional - Failed int32 `json:"failed"` -} - -// GetJobList returns a list of all Jobs in the cluster. -func GetJobList(client *kubernetes.Clientset, nsQuery *k8scommon.NamespaceQuery, dsQuery *dataselect.DataSelectQuery) (*JobList, error) { - global.Log.Info("Getting list of all jobs in the cluster") - - channels := &k8scommon.ResourceChannels{ - JobList: k8scommon.GetJobListChannel(client, nsQuery, 1), - PodList: k8scommon.GetPodListChannel(client, nsQuery, 1), - EventList: k8scommon.GetEventListChannel(client, nsQuery, 1), - } - - return GetJobListFromChannels(channels, dsQuery) -} - -// GetJobListFromChannels returns a list of all Jobs in the cluster reading required resource list once from the channels. -func GetJobListFromChannels(channels *k8scommon.ResourceChannels, dsQuery *dataselect.DataSelectQuery) (*JobList, error) { - - jobs := <-channels.JobList.List - err := <-channels.JobList.Error - if err != nil { - return nil, err - } - - pods := <-channels.PodList.List - err = <-channels.PodList.Error - if err != nil { - return nil, err - } - - events := <-channels.EventList.List - err = <-channels.EventList.Error - if err != nil { - return nil, err - } - - jobList := ToJobList(jobs.Items, pods.Items, events.Items, dsQuery) - jobList.Status = getStatus(jobs, pods.Items) - return jobList, nil -} - -func ToJobList(jobs []batch.Job, pods []v1.Pod, events []v1.Event, dsQuery *dataselect.DataSelectQuery) *JobList { - - jobList := &JobList{ - Jobs: make([]Job, 0), - ListMeta: k8s.ListMeta{TotalItems: len(jobs)}, - } - - jobCells, filteredTotal := dataselect.GenericDataSelectWithFilter(ToCells(jobs), dsQuery) - jobs = FromCells(jobCells) - jobList.ListMeta = k8s.ListMeta{TotalItems: filteredTotal} - - for _, job := range jobs { - matchingPods := k8scommon.FilterPodsForJob(job, pods) - podInfo := k8scommon.GetPodInfo(job.Status.Active, job.Spec.Completions, matchingPods) - podInfo.Warnings = event.GetPodsEventWarnings(events, matchingPods) - jobList.Jobs = append(jobList.Jobs, toJob(&job, &podInfo)) - } - - return jobList -} - -func toJob(job *batch.Job, podInfo *k8scommon.PodInfo) Job { - - return Job{ - ObjectMeta: k8s.NewObjectMeta(job.ObjectMeta), - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindJob), - ContainerImages: k8scommon.GetContainerImages(&job.Spec.Template.Spec), - InitContainerImages: k8scommon.GetInitContainerImages(&job.Spec.Template.Spec), - Pods: *podInfo, - JobStatus: GetJobStatus(job), - PodStatus: GetPodStatus(job), - Parallelism: job.Spec.Parallelism, - } -} - -func GetJobStatus(job *batch.Job) JobStatus { - jobStatus := JobStatus{Status: JobStatusRunning, Conditions: getJobConditions(job)} - for _, condition := range job.Status.Conditions { - if condition.Type == batch.JobComplete && condition.Status == v1.ConditionTrue { - jobStatus.Status = JobStatusComplete - break - } else if condition.Type == batch.JobFailed && condition.Status == v1.ConditionTrue { - jobStatus.Status = JobStatusFailed - jobStatus.Message = condition.Message - break - } - } - return jobStatus -} - -func getJobConditions(job *batch.Job) []k8scommon.Condition { - var conditions []k8scommon.Condition - for _, condition := range job.Status.Conditions { - conditions = append(conditions, k8scommon.Condition{ - Type: string(condition.Type), - Status: meta.ConditionStatus(condition.Status), - LastProbeTime: condition.LastProbeTime, - LastTransitionTime: condition.LastTransitionTime, - Reason: condition.Reason, - Message: condition.Message, - }) - } - return conditions -} - -func GetPodStatus(job *batch.Job) PodStatus { - - return PodStatus{ - Active: job.Status.Active, - Succeeded: job.Status.Succeeded, - Failed: job.Status.Failed, - StartTime: job.Status.StartTime, - CompletionTime: job.Status.CompletionTime, - } - -} - -func DeleteJob(client *kubernetes.Clientset, namespace, name string) (err error) { - return client.BatchV1().Jobs(namespace).Delete(context.TODO(), name, meta.DeleteOptions{}) -} - -func DeleteCollectionJob(client *kubernetes.Clientset, jobList []k8s.JobData) (err error) { - global.Log.Info("批量删除job开始") - for _, v := range jobList { - global.Log.Info(fmt.Sprintf("delete job:%v, ns: %v", v.Name, v.Namespace)) - err := client.BatchV1().Jobs(v.Namespace).Delete( - context.TODO(), - v.Name, - meta.DeleteOptions{}, - ) - if err != nil { - global.Log.Error(err.Error()) - return err - } - } - global.Log.Info("删除job已完成") - return nil -} - -func ScaleJob(client *kubernetes.Clientset, namespace, name string, scaleNumber *int32) (err error) { - job, err := client.BatchV1().Jobs(namespace).Get(context.TODO(), name, meta.GetOptions{}) - if err != nil { - return err - } - job.Spec.Parallelism = scaleNumber - _, err = client.BatchV1().Jobs(namespace).Update(context.TODO(), job, meta.UpdateOptions{}) - if err != nil { - return err - } - return nil -} diff --git a/apps/devops/services/k8s/job/job_common.go b/apps/devops/services/k8s/job/job_common.go deleted file mode 100644 index 823e68f..0000000 --- a/apps/devops/services/k8s/job/job_common.go +++ /dev/null @@ -1,67 +0,0 @@ -package job - -import ( - batch "k8s.io/api/batch/v1" - v1 "k8s.io/api/core/v1" - "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" -) - -// The code below allows to perform complex data section on []batch.Job - -type JobCell batch.Job - -func (self JobCell) GetProperty(name dataselect.PropertyName) dataselect.ComparableValue { - switch name { - case dataselect.NameProperty: - return dataselect.StdComparableString(self.ObjectMeta.Name) - case dataselect.CreationTimestampProperty: - return dataselect.StdComparableTime(self.ObjectMeta.CreationTimestamp.Time) - case dataselect.NamespaceProperty: - return dataselect.StdComparableString(self.ObjectMeta.Namespace) - default: - // if name is not supported then just return a constant dummy value, sort will have no effect. - return nil - } -} - -func ToCells(std []batch.Job) []dataselect.DataCell { - cells := make([]dataselect.DataCell, len(std)) - for i := range std { - cells[i] = JobCell(std[i]) - } - return cells -} - -func FromCells(cells []dataselect.DataCell) []batch.Job { - std := make([]batch.Job, len(cells)) - for i := range std { - std[i] = batch.Job(cells[i].(JobCell)) - } - return std -} - -func getStatus(list *batch.JobList, pods []v1.Pod) common.ResourceStatus { - info := common.ResourceStatus{} - if list == nil { - return info - } - - for _, job := range list.Items { - matchingPods := common.FilterPodsForJob(job, pods) - podInfo := common.GetPodInfo(job.Status.Active, job.Spec.Completions, matchingPods) - jobStatus := GetJobStatus(&job) - - if jobStatus.Status == JobStatusFailed { - info.Failed++ - } else if jobStatus.Status == JobStatusComplete { - info.Succeeded++ - } else if podInfo.Running > 0 { - info.Running++ - } else { - info.Pending++ - } - } - - return info -} diff --git a/apps/devops/services/k8s/job/job_detail.go b/apps/devops/services/k8s/job/job_detail.go deleted file mode 100644 index f8d369e..0000000 --- a/apps/devops/services/k8s/job/job_detail.go +++ /dev/null @@ -1,46 +0,0 @@ -package job - -import ( - "context" - batch "k8s.io/api/batch/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/services/k8s/common" -) - -// JobDetail is a presentation layer view of Kubernetes Job resource. -type JobDetail struct { - // Extends list item structure. - Job `json:",inline"` - Status []batch.JobCondition `json:"status"` - // Completions specifies the desired number of successfully finished pods the job should be run with. - Completions *int32 `json:"completions"` - - PodList *PodList `json:"podList"` -} - -// GetJobDetail gets job details. -func GetJobDetail(client *kubernetes.Clientset, namespace, name string) (*JobDetail, error) { - jobData, err := client.BatchV1().Jobs(namespace).Get(context.TODO(), name, metaV1.GetOptions{}) - if err != nil { - return nil, err - } - - podInfo, err := getJobPodInfo(client, jobData) - if err != nil { - return nil, err - } - - job := toJobDetail(client, jobData, *podInfo) - return &job, nil -} - -func toJobDetail(client *kubernetes.Clientset, job *batch.Job, podInfo common.PodInfo) JobDetail { - - return JobDetail{ - Job: toJob(job, &podInfo), - Status: job.Status.Conditions, - Completions: job.Spec.Completions, - PodList: getJobToPod(client, job), - } -} diff --git a/apps/devops/services/k8s/job/pods.go b/apps/devops/services/k8s/job/pods.go deleted file mode 100644 index 5f960d4..0000000 --- a/apps/devops/services/k8s/job/pods.go +++ /dev/null @@ -1,78 +0,0 @@ -package job - -import ( - "context" - "pandax/base/global" - - "go.uber.org/zap" - batch "k8s.io/api/batch/v1" - v1 "k8s.io/api/core/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/event" - "pandax/apps/devops/services/k8s/pods" -) - -type PodList struct { - ListMeta k8s.ListMeta `json:"listMeta"` - - // Basic information about resources status on the list. - Status k8scommon.ResourceStatus `json:"status"` - - // Unordered list of Pods. - Pods []pods.Pod `json:"pods"` -} - -// Returns simple info about pods(running, desired, failing, etc.) related to given job. -func getJobPodInfo(client *kubernetes.Clientset, job *batch.Job) (*k8scommon.PodInfo, error) { - labelSelector := labels.SelectorFromSet(job.Spec.Selector.MatchLabels) - channels := &k8scommon.ResourceChannels{ - PodList: k8scommon.GetPodListChannelWithOptions(client, k8scommon.NewSameNamespaceQuery( - job.Namespace), - metaV1.ListOptions{ - LabelSelector: labelSelector.String(), - FieldSelector: fields.Everything().String(), - }, 1), - } - - podList := <-channels.PodList.List - if err := <-channels.PodList.Error; err != nil { - return nil, err - } - - podInfo := k8scommon.GetPodInfo(job.Status.Active, job.Spec.Completions, podList.Items) - - // This pod info for jobs should be get from job status, similar to kubectl describe logic. - podInfo.Running = job.Status.Active - podInfo.Succeeded = job.Status.Succeeded - podInfo.Failed = job.Status.Failed - return &podInfo, nil -} - -func getJobToPod(client *kubernetes.Clientset, job *batch.Job) (po *PodList) { - - selector, err := metaV1.LabelSelectorAsSelector(job.Spec.Selector) - if err != nil { - return nil - } - options := metaV1.ListOptions{LabelSelector: selector.String()} - - podData, err := client.CoreV1().Pods(job.Namespace).List(context.TODO(), options) - if err != nil { - global.Log.Error("Get a pod exception from the job", zap.Any("err", err)) - } - podList := PodList{ - Pods: make([]pods.Pod, 0), - } - podList.ListMeta = k8s.ListMeta{TotalItems: len(podData.Items)} - for _, pod := range podData.Items { - warnings := event.GetPodsEventWarnings(nil, []v1.Pod{pod}) - podDetail := pods.ToPod(&pod, warnings) - podList.Pods = append(podList.Pods, podDetail) - } - return &podList -} diff --git a/apps/devops/services/k8s/logs/logs.go b/apps/devops/services/k8s/logs/logs.go deleted file mode 100644 index 097a400..0000000 --- a/apps/devops/services/k8s/logs/logs.go +++ /dev/null @@ -1,252 +0,0 @@ -package logs - -import ( - "sort" - "strings" -) - -// LineIndexNotFound is returned if requested line could not be found -var LineIndexNotFound = -1 - -// DefaultDisplayNumLogLines returns default number of lines in case of invalid request. -var DefaultDisplayNumLogLines = 100 - -// MaxLogLines is a number that will be certainly bigger than any number of logs. Here 2 billion logs is certainly much larger -// number of log lines than we can handle. -var MaxLogLines int = 2000000000 - -const ( - NewestTimestamp = "newest" - OldestTimestamp = "oldest" -) - -// Load logs from the beginning or the end of the log file. -// This matters only if the log file is too large to be loaded completely. -const ( - Beginning = "beginning" - End = "end" -) - -// NewestLogLineId is the reference Id of the newest line. -var NewestLogLineId = LogLineId{ - LogTimestamp: NewestTimestamp, -} - -// OldestLogLineId is the reference Id of the oldest line. -var OldestLogLineId = LogLineId{ - LogTimestamp: OldestTimestamp, -} - -// DefaultSelection loads default log view selector that is used in case of invalid request -// Downloads newest DefaultDisplayNumLogLines lines. -var DefaultSelection = &Selection{ - OffsetFrom: 1 - DefaultDisplayNumLogLines, - OffsetTo: 1, - ReferencePoint: NewestLogLineId, - LogFilePosition: End, -} - -// AllSelection returns all logs. -var AllSelection = &Selection{ - OffsetFrom: -MaxLogLines, - OffsetTo: MaxLogLines, - ReferencePoint: NewestLogLineId, -} - -// LogDetails returns representation of log lines -type LogDetails struct { - - // Additional information of the logs e.g. container name, dates,... - Info LogInfo `json:"info"` - - // Reference point to keep track of the position of all the logs - Selection `json:"selection"` - - // Actual log lines of this page - LogLines `json:"logs"` -} - -// LogInfo returns meta information about the selected log lines -type LogInfo struct { - - // Pod name. - PodName string `json:"podName"` - - // The name of the container the logs are for. - ContainerName string `json:"containerName"` - - // The name of the init container the logs are for. - InitContainerName string `json:"initContainerName"` - - // Date of the first log line - FromDate LogTimestamp `json:"fromDate"` - - // Date of the last log line - ToDate LogTimestamp `json:"toDate"` - - // Some log lines in the middle of the log file could not be loaded, because the log file is too large. - Truncated bool `json:"truncated"` -} - -// Selection of a slice of logs. -// It works just like normal slicing, but indices are referenced relatively to certain reference line. -// So for example if reference line has index n and we want to download first 10 elements in array we have to use -// from -n to -n+10. Setting ReferenceLogLineId the first line will result in standard slicing. -type Selection struct { - // ReferencePoint is the ID of a line which should serve as a reference point for this selector. - // You can set it to last or first line if needed. Setting to the first line will result in standard slicing. - ReferencePoint LogLineId `json:"referencePoint"` - // First index of the slice relatively to the reference line(this one will be included). - OffsetFrom int `json:"offsetFrom"` - // Last index of the slice relatively to the reference line (this one will not be included). - OffsetTo int `json:"offsetTo"` - // The log file is loaded either from the beginning or from the end. This matters only if the log file is too - // large to be handled and must be truncated (to avoid oom) - LogFilePosition string `json:"logFilePosition"` -} - -// LogLineId uniquely identifies a line in logs - immune to log addition/deletion. -type LogLineId struct { - // timestamp of this line. - LogTimestamp `json:"timestamp"` - // in case of timestamp duplicates (rather unlikely) it gives the index of the duplicate. - // For example if this LogTimestamp appears 3 times in the logs and the line is 1nd line with this timestamp, - // then line num will be 1 or -3 (1st from beginning or 3rd from the end). - // If timestamp is unique then it will be simply 1 or -1 (first from the beginning or first from the end, both mean the same). - LineNum int `json:"lineNum"` -} - -// LogLines provides means of selecting log views. Problem with logs is that new logs are constantly added. -// Therefore the number of logs constantly changes and we cannot use normal indexing. For example -// if certain line has index N then it may not have index N anymore 1 second later as logs at the beginning of the list -// are being deleted. Therefore it is necessary to reference log indices relative to some line that we are certain will not be deleted. -// For example line in the middle of logs should have lifetime sufficiently long for the purposes of log visualisation. On average its lifetime -// is equal to half of the log retention time. Therefore line in the middle of logs would serve as a good reference point. -// LogLines allows to get ID of any line - this ID later allows to uniquely identify this line. Also it allows to get any -// slice of logs relatively to certain reference line ID. -type LogLines []LogLine - -// LogLine is a single log line that split into timestamp and the actual content. -type LogLine struct { - Timestamp LogTimestamp `json:"timestamp"` - Content string `json:"content"` -} - -// LogTimestamp is a timestamp that appears on the beginning of each log line. -type LogTimestamp string - -// SelectLogs returns selected part of LogLines as required by logSelector, moreover it returns IDs of first and last -// of returned lines and the information of the resulting logView. -func (self LogLines) SelectLogs(logSelection *Selection) (LogLines, LogTimestamp, LogTimestamp, Selection, bool) { - requestedNumItems := logSelection.OffsetTo - logSelection.OffsetFrom - referenceLineIndex := self.getLineIndex(&logSelection.ReferencePoint) - if referenceLineIndex == LineIndexNotFound || requestedNumItems <= 0 || len(self) == 0 { - // Requested reference line could not be found, probably it's already gone or requested no logs. Return no logs. - return LogLines{}, "", "", Selection{}, false - } - fromIndex := referenceLineIndex + logSelection.OffsetFrom - toIndex := referenceLineIndex + logSelection.OffsetTo - lastPage := false - if requestedNumItems > len(self) { - fromIndex = 0 - toIndex = len(self) - lastPage = true - } else if toIndex > len(self) { - fromIndex -= toIndex - len(self) - toIndex = len(self) - lastPage = logSelection.LogFilePosition == Beginning - } else if fromIndex < 0 { - toIndex += -fromIndex - fromIndex = 0 - lastPage = logSelection.LogFilePosition == End - } - - // set the middle of log array as a reference point, this part of array should not be affected by log deletion/addition. - newSelection := Selection{ - ReferencePoint: *self.createLogLineId(len(self) / 2), - OffsetFrom: fromIndex - len(self)/2, - OffsetTo: toIndex - len(self)/2, - LogFilePosition: logSelection.LogFilePosition, - } - return self[fromIndex:toIndex], self[fromIndex].Timestamp, self[toIndex-1].Timestamp, newSelection, lastPage -} - -// getLineIndex returns the index of the line (referenced from beginning of log array) with provided logLineId. -func (self LogLines) getLineIndex(logLineId *LogLineId) int { - if logLineId == nil || logLineId.LogTimestamp == NewestTimestamp || len(self) == 0 || logLineId.LogTimestamp == "" { - // if no line id provided return index of last item. - return len(self) - 1 - } else if logLineId.LogTimestamp == OldestTimestamp { - return 0 - } - logTimestamp := logLineId.LogTimestamp - - matchingStartedAt := 0 - matchingStartedAt = sort.Search(len(self), func(i int) bool { - return self[i].Timestamp >= logTimestamp - }) - - linesMatched := 0 - if matchingStartedAt < len(self) && self[matchingStartedAt].Timestamp == logTimestamp { // match found - for (matchingStartedAt+linesMatched) < len(self) && self[matchingStartedAt+linesMatched].Timestamp == logTimestamp { - linesMatched += 1 - } - } - - var offset int - if logLineId.LineNum < 0 { - offset = linesMatched + logLineId.LineNum - } else { - offset = logLineId.LineNum - 1 - } - if 0 <= offset && offset < linesMatched { - return matchingStartedAt + offset - } - return LineIndexNotFound -} - -// createLogLineId returns ID of the line with provided lineIndex. -func (self LogLines) createLogLineId(lineIndex int) *LogLineId { - logTimestamp := self[lineIndex].Timestamp - // determine whether to use negative or positive indexing - // check whether last line has the same index as requested line. If so, we can only use positive referencing - // as more lines may appear at the end. - // negative referencing is preferred as higher indices disappear later. - var step int - if self[len(self)-1].Timestamp == logTimestamp { - // use positive referencing - step = 1 - } else { - step = -1 - } - offset := step - for ; 0 <= lineIndex-offset && lineIndex-offset < len(self); offset += step { - if self[lineIndex-offset].Timestamp != logTimestamp { - break - } - } - return &LogLineId{ - LogTimestamp: logTimestamp, - LineNum: offset, - } -} - -// ToLogLines converts rawLogs (string) to LogLines. Proper log lines start with a timestamp which is chopped off. -// In error cases the server returns a message without a timestamp -func ToLogLines(rawLogs string) LogLines { - logLines := LogLines{} - for _, line := range strings.Split(rawLogs, "\n") { - if line != "" { - startsWithDate := ('0' <= line[0] && line[0] <= '9') //2017-... - idx := strings.Index(line, " ") - if idx > 0 && startsWithDate { - timestamp := LogTimestamp(line[0:idx]) - content := line[idx+1:] - logLines = append(logLines, LogLine{Timestamp: timestamp, Content: content}) - } else { - logLines = append(logLines, LogLine{Timestamp: LogTimestamp("0"), Content: line}) - } - } - } - return logLines -} diff --git a/apps/devops/services/k8s/logs/source.go b/apps/devops/services/k8s/logs/source.go deleted file mode 100644 index 8069a2e..0000000 --- a/apps/devops/services/k8s/logs/source.go +++ /dev/null @@ -1,45 +0,0 @@ -package logs - -import ( - "context" - meta "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/controller" -) - -// GetLogSources returns all log sources for a given resource. A log source identifies a log file through the combination of pod & container -func GetLogSources(k8sClient kubernetes.Interface, ns string, resourceName string, resourceType string) (controller.LogSources, error) { - if resourceType == "pod" { - return getLogSourcesFromPod(k8sClient, ns, resourceName) - } - return getLogSourcesFromController(k8sClient, ns, resourceName, resourceType) -} - -// GetLogSourcesFromPod returns all containers for a given pod -func getLogSourcesFromPod(k8sClient kubernetes.Interface, ns, resourceName string) (controller.LogSources, error) { - pod, err := k8sClient.CoreV1().Pods(ns).Get(context.TODO(), resourceName, meta.GetOptions{}) - if err != nil { - return controller.LogSources{}, err - } - return controller.LogSources{ - ContainerNames: common.GetContainerNames(&pod.Spec), - InitContainerNames: common.GetInitContainerNames(&pod.Spec), - PodNames: []string{resourceName}, - }, nil -} - -// GetLogSourcesFromController returns all pods and containers for a controller object, such as ReplicaSet -func getLogSourcesFromController(k8sClient kubernetes.Interface, ns, resourceName, resourceType string) (controller.LogSources, error) { - ref := meta.OwnerReference{Kind: resourceType, Name: resourceName} - rc, err := controller.NewResourceController(ref, ns, k8sClient) - if err != nil { - return controller.LogSources{}, err - } - allPods, err := k8sClient.CoreV1().Pods(ns).List(context.TODO(), k8s.ListEverything) - if err != nil { - return controller.LogSources{}, err - } - return rc.GetLogSources(allPods.Items), nil -} diff --git a/apps/devops/services/k8s/namespace/namespace.go b/apps/devops/services/k8s/namespace/namespace.go deleted file mode 100644 index 8d3e945..0000000 --- a/apps/devops/services/k8s/namespace/namespace.go +++ /dev/null @@ -1,17 +0,0 @@ -package namespace - -import ( - "context" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" -) - -func GetNamespaceList(client *kubernetes.Clientset) (*v1.NamespaceList, error) { - - namespace, err := client.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{}) - if err != nil { - return nil, err - } - return namespace, nil -} diff --git a/apps/devops/services/k8s/node/node.go b/apps/devops/services/k8s/node/node.go deleted file mode 100644 index b348d32..0000000 --- a/apps/devops/services/k8s/node/node.go +++ /dev/null @@ -1,272 +0,0 @@ -package node - -import ( - "context" - "errors" - "fmt" - "pandax/base/global" - - "github.com/gin-gonic/gin" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - "pandax/apps/devops/services/k8s/dataselect" - "pandax/apps/devops/services/k8s/evict" - "pandax/apps/devops/services/k8s/parser" - "time" -) - -// NodeList 包含集群中的节点列表. -type NodeList struct { - ListMeta k8s.ListMeta `json:"listMeta"` - Nodes []Node `json:"nodes"` -} - -// Node is a presentation layer view of Kubernetes nodes. This means it is node plus additional -// augmented data we can get from other sources. -type Node struct { - ObjectMeta k8s.ObjectMeta `json:"objectMeta"` - TypeMeta k8s.TypeMeta `json:"typeMeta"` - Ready v1.ConditionStatus `json:"ready"` - Unschedulable k8s.Unschedulable `json:"unschedulable"` - NodeIP k8s.NodeIP `json:"nodeIP"` - AllocatedResources k8s.NodeAllocatedResources `json:"allocatedResources"` - NodeInfo v1.NodeSystemInfo `json:"nodeInfo"` - //RuntimeType string `json:"runtimeType"` -} - -func GetNodeList(client *kubernetes.Clientset, dsQuery *gin.Context) (*NodeList, error) { - /* - 获取所有Node节点信息 - */ - - nodes, err := client.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{}) - if err != nil { - return nil, fmt.Errorf("get nodes from cluster failed: %v", err) - } - - return toNodeList(client, nodes.Items, dsQuery), nil -} - -func toNodeList(client *kubernetes.Clientset, nodes []v1.Node, dsQuery *gin.Context) *NodeList { - - nodeList := &NodeList{ - Nodes: make([]Node, 0), // make初始化node信息 - ListMeta: k8s.ListMeta{TotalItems: len(nodes)}, // 计算node数量 - } - // 解析前端传递的参数, filterBy=name,1.1&itemsPerPage=10&name=&namespace=default&page=1&sortBy=d,creationTimestamp - // sortBy=d 倒序, sortBy=a 正序, 排序按照a-z - dataSelect := parser.ParseDataSelectPathParameter(dsQuery) - // 过滤 - nodeCells, filteredTotal := dataselect.GenericDataSelectWithFilter(toCells(nodes), dataSelect) - nodes = fromCells(nodeCells) - // 更新node数量, filteredTotal过滤后的数量 - nodeList.ListMeta = k8s.ListMeta{TotalItems: filteredTotal} - - for _, node := range nodes { - // 根据Node名称去获取节点上面的pod,过滤时排除pod为 Succeeded, Failed 返回pods - pods, err := getNodePods(client, node) - if err != nil { - global.Log.Error(fmt.Sprintf("Couldn't get pods of %s node: %s\n", node.Name, err)) - } - - // 调用toNode方法获取 node节点的计算资源 - nodeList.Nodes = append(nodeList.Nodes, toNode(node, pods, getNodeRole(node))) - } - - return nodeList -} - -func toNode(node v1.Node, pods *v1.PodList, role string) Node { - // 获取cpu和内存的reqs, limits使用 - allocatedResources, err := getNodeAllocatedResources(node, pods) - if err != nil { - global.Log.Error(fmt.Sprintf("Couldn't get allocated resources of %s node: %s\n", node.Name, err)) - } - - return Node{ - ObjectMeta: k8s.NewObjectMeta(node.ObjectMeta), - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKind(role)), - Ready: getNodeConditionStatus(node, v1.NodeReady), - NodeIP: k8s.NodeIP(getNodeIP(node)), - Unschedulable: k8s.Unschedulable(node.Spec.Unschedulable), - AllocatedResources: allocatedResources, - NodeInfo: node.Status.NodeInfo, - } -} - -func getNodeConditionStatus(node v1.Node, conditionType v1.NodeConditionType) v1.ConditionStatus { - for _, condition := range node.Status.Conditions { - if condition.Type == conditionType { - return condition.Status - } - } - return v1.ConditionUnknown -} - -func getNodeIP(node v1.Node) string { - for _, addr := range node.Status.Addresses { - if addr.Type == v1.NodeInternalIP { - return addr.Address - } - } - return "" -} - -func getNodeRole(node v1.Node) string { - var role string - if _, ok := node.ObjectMeta.Labels["node-role.kubernetes.io/master"]; ok { - role = "Master" - } else { - role = "Worker" - } - return role -} - -func GetNodeResource(client *kubernetes.Clientset) (namespaces int, deployments int, pods int) { - /* - 获取集群 namespace数量 deployment数量 pod数量 container数量 - */ - namespace, err := client.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{}) - namespaces = len(namespace.Items) - if err != nil { - global.Log.Error("list namespace err") - } - for _, v := range namespace.Items { - deployment, err := client.AppsV1().Deployments(v.Name).List(context.TODO(), metav1.ListOptions{}) - deployments += len(deployment.Items) - if err != nil { - global.Log.Error("get deployment err") - } - pod, err := client.CoreV1().Pods(v.Name).List(context.TODO(), metav1.ListOptions{}) - if err != nil { - global.Log.Error("get pod err") - } - pods += len(pod.Items) - } - - return namespaces, deployments, pods -} - -func NodeUnschdulable(client *kubernetes.Clientset, nodeName string, unschdulable bool) (bool, error) { - /* - 设置节点是否可调度 - */ - global.Log.Info(fmt.Sprintf("设置Node节点:%v 不可调度: %v", nodeName, unschdulable)) - node, err := client.CoreV1().Nodes().Get(context.TODO(), nodeName, metav1.GetOptions{}) - if err != nil { - global.Log.Error(fmt.Sprintf("get node err: %v", err.Error())) - return false, err - } - node.Spec.Unschedulable = unschdulable - - _, err2 := client.CoreV1().Nodes().Update(context.TODO(), node, metav1.UpdateOptions{}) - - if err2 != nil { - global.Log.Error(fmt.Sprintf("设置节点调度失败:%v", err2.Error())) - return false, err2 - } - return true, nil -} - -func CordonNode(client *kubernetes.Clientset, nodeName string) (bool, error) { - /* - 排空节点 - 选择排空节点(同时设置为不可调度),在后续进行应用部署时,则Pod不会再调度到该节点,并且该节点上由DaemonSet控制的Pod不会被排空。 - kubectl drain cn-beijing.i-2ze19qyi8votgjz12345 --grace-period=120 --ignore-daemonsets=true - */ - _, err := NodeUnschdulable(client, nodeName, true) - if err != nil { - return false, err - } - err = evict.EvictsNodePods(client, nodeName) - if err != nil { - global.Log.Error(fmt.Sprintf("排空节点出现异常: %v", err.Error())) - return false, err - } - return true, nil - -} - -func RemoveNode(client *kubernetes.Clientset, nodeName string) (bool, error) { - startTime := time.Now() - global.Log.Info(fmt.Sprintf("移除Node节点:%v, 异步任务已开始", nodeName)) - _, err := NodeUnschdulable(client, nodeName, true) - if err != nil { - return false, err - } - err = evict.EvictsNodePods(client, nodeName) - if err != nil { - global.Log.Error(fmt.Sprintf("排空节点出现异常: %v", err.Error())) - return false, err - } - err2 := client.CoreV1().Nodes().Delete(context.TODO(), nodeName, metav1.DeleteOptions{}) - if err2 != nil { - return false, err2 - } - global.Log.Info(fmt.Sprintf("已将节点:%v从集群中移除, 异步任务已完成,任务耗时:%v", nodeName, time.Since(startTime))) - - return true, nil -} - -func CollectionNodeUnschedule(client *kubernetes.Clientset, nodeName []string) error { - /* - 批量设置Node节点不可调度 - {"node_name": ["k8s-master", "k8s-node"]} - */ - if len(nodeName) <= 0 { - return errors.New("节点名称不能为空") - } - global.Log.Info(fmt.Sprintf("批量设置Node节点:%v 不可调度:true", nodeName)) - for _, v := range nodeName { - node, err := client.CoreV1().Nodes().Get(context.TODO(), v, metav1.GetOptions{}) - if err != nil { - global.Log.Error(fmt.Sprintf("get node err: %v", err.Error())) - return err - } - node.Spec.Unschedulable = true - - _, err2 := client.CoreV1().Nodes().Update(context.TODO(), node, metav1.UpdateOptions{}) - - if err2 != nil { - global.Log.Error(fmt.Sprintf("设置节点调度失败:%v", err2.Error())) - return err - } - } - global.Log.Info(fmt.Sprintf("已将所有Node节点:%v 设置为不可调度", nodeName)) - return nil -} - -func CollectionCordonNode(client *kubernetes.Clientset, nodeName []string) error { - /* - 批量排空Node节点, 不允许调度 - {"node_name": ["k8s-master", "k8s-node"]} - */ - - if len(nodeName) <= 0 { - return errors.New("节点名称不能为空") - } - global.Log.Info(fmt.Sprintf("开始排空节点, 设置Node节点:%v 不可调度:true", nodeName)) - for _, v := range nodeName { - node, err := client.CoreV1().Nodes().Get(context.TODO(), v, metav1.GetOptions{}) - if err != nil { - global.Log.Error(fmt.Sprintf("get node err: %v", err.Error())) - return err - } - node.Spec.Unschedulable = true - - _, err2 := client.CoreV1().Nodes().Update(context.TODO(), node, metav1.UpdateOptions{}) - - if err2 != nil { - global.Log.Error(fmt.Sprintf("设置节点调度失败:%v", err2.Error())) - return err - } - _, cordonErr := CordonNode(client, v) - if cordonErr != nil { - return cordonErr - } - } - global.Log.Info(fmt.Sprintf("已将所有Node节点:%v 设置为不可调度", nodeName)) - return nil -} diff --git a/apps/devops/services/k8s/node/node_common.go b/apps/devops/services/k8s/node/node_common.go deleted file mode 100644 index 36c47c1..0000000 --- a/apps/devops/services/k8s/node/node_common.go +++ /dev/null @@ -1,68 +0,0 @@ -package node - -import ( - v1 "k8s.io/api/core/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" -) - -type NodeCell v1.Node - -func (self NodeCell) GetProperty(name dataselect.PropertyName) dataselect.ComparableValue { - switch name { - case dataselect.NameProperty: - return dataselect.StdComparableString(self.ObjectMeta.Name) - case dataselect.CreationTimestampProperty: - return dataselect.StdComparableTime(self.ObjectMeta.CreationTimestamp.Time) - case dataselect.NamespaceProperty: - return dataselect.StdComparableString(self.ObjectMeta.Namespace) - default: - // if name is not supported then just return a constant dummy value, sort will have no effect. - return nil - } -} - -func toCells(std []v1.Node) []dataselect.DataCell { - cells := make([]dataselect.DataCell, len(std)) - - for i := range std { - cells[i] = NodeCell(std[i]) - - } - return cells -} - -func fromCells(cells []dataselect.DataCell) []v1.Node { - std := make([]v1.Node, len(cells)) - for i := range std { - std[i] = v1.Node(cells[i].(NodeCell)) - } - return std -} - -func getNodeConditions(node v1.Node) []common.Condition { - var conditions []common.Condition - for _, condition := range node.Status.Conditions { - conditions = append(conditions, common.Condition{ - Type: string(condition.Type), - Status: metaV1.ConditionStatus(condition.Status), - LastProbeTime: condition.LastHeartbeatTime, - LastTransitionTime: condition.LastTransitionTime, - Reason: condition.Reason, - Message: condition.Message, - }) - } - return conditions -} - -//getContainerImages returns container image strings from the given node. -func getContainerImages(node v1.Node) []string { - var containerImages []string - for _, image := range node.Status.Images { - for _, name := range image.Names { - containerImages = append(containerImages, name) - } - } - return containerImages -} diff --git a/apps/devops/services/k8s/node/node_detail.go b/apps/devops/services/k8s/node/node_detail.go deleted file mode 100644 index ce53045..0000000 --- a/apps/devops/services/k8s/node/node_detail.go +++ /dev/null @@ -1,295 +0,0 @@ -package node - -import ( - "context" - "fmt" - "pandax/apps/devops/services/k8s/event" - "pandax/base/global" - - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - //"github.com/gin-gonic/gin" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/client-go/kubernetes" -) - -// NodeAllocatedResources describes node allocated resources. -type NodeAllocatedResources struct { - // CPURequests is number of allocated milicores. - CPURequests int64 `json:"cpuRequests"` - - // CPURequestsFraction is a fraction of CPU, that is allocated. - CPURequestsFraction float64 `json:"cpuRequestsFraction"` - - // CPULimits is defined CPU limit. - CPULimits int64 `json:"cpuLimits"` - - // CPULimitsFraction is a fraction of defined CPU limit, can be over 100%, i.e. - // overcommitted. - CPULimitsFraction float64 `json:"cpuLimitsFraction"` - - // CPUCapacity is specified node CPU capacity in milicores. - CPUCapacity int64 `json:"cpuCapacity"` - - // MemoryRequests is a fraction of memory, that is allocated. - MemoryRequests int64 `json:"memoryRequests"` - - // MemoryRequestsFraction is a fraction of memory, that is allocated. - MemoryRequestsFraction float64 `json:"memoryRequestsFraction"` - - // MemoryLimits is defined memory limit. - MemoryLimits int64 `json:"memoryLimits"` - - // MemoryLimitsFraction is a fraction of defined memory limit, can be over 100%, i.e. - // overcommitted. - MemoryLimitsFraction float64 `json:"memoryLimitsFraction"` - - // MemoryCapacity is specified node memory capacity in bytes. - MemoryCapacity int64 `json:"memoryCapacity"` - - // AllocatedPods in number of currently allocated pods on the node. - AllocatedPods int `json:"allocatedPods"` - - // PodCapacity is maximum number of pods, that can be allocated on the node. - PodCapacity int64 `json:"podCapacity"` - - // PodFraction is a fraction of pods, that can be allocated on given node. - PodFraction float64 `json:"podFraction"` -} - -// NodeDetail is a presentation layer view of Kubernetes Node resource. This means it is Node plus -// additional augmented data we can get from other sources. -type NodeDetail struct { - // Extends list item structure. - Node `json:",inline"` - - // NodePhase is the current lifecycle phase of the node. - Phase v1.NodePhase `json:"phase"` - - // PodCIDR represents the pod IP range assigned to the node. - PodCIDR string `json:"podCIDR"` - - // ID of the node assigned by the cloud provider. - ProviderID string `json:"providerID"` - - // Unschedulable controls node schedulability of new pods. By default node is schedulable. - Unschedulable bool `json:"unschedulable"` - - // Set of ids/uuids to uniquely identify the node. - NodeInfo v1.NodeSystemInfo `json:"nodeInfo"` - - //// Conditions is an array of current node conditions. - Conditions []k8scommon.Condition `json:"conditions"` - - // Container images of the node. - ContainerImages []string `json:"containerImages"` - - // PodListComponent contains information about pods belonging to this node. - PodList v1.PodList `json:"podList"` - - // Events is list of events associated to the node. - EventList v1.EventList `json:"eventList"` - - // Taints - Taints []v1.Taint `json:"taints,omitempty"` - - // Addresses is a list of addresses reachable to the node. Queried from cloud provider, if available. - Addresses []v1.NodeAddress `json:"addresses,omitempty"` - - Ready v1.ConditionStatus `json:"ready"` - NodeIP k8s.NodeIP `json:"nodeIP"` - UID k8s.UID `json:"uid"` -} - -func GetNodeDetail(client *kubernetes.Clientset, name string) (*NodeDetail, error) { - /* - 获取节点详细信息 - */ - global.Log.Info(fmt.Sprintf("Getting details of %s node", name)) - - node, err := client.CoreV1().Nodes().Get(context.TODO(), name, metaV1.GetOptions{}) - - if err != nil { - return nil, err - } - - pods, err := getNodePods(client, *node) - if err != nil { - return nil, err - } - - eventList, err := event.GetNodeEvents(client, node.Name) - if err != nil { - return nil, err - } - - allocatedResources, err := getNodeAllocatedResources(*node, pods) - if err != nil { - return nil, err - } - - nodeDetails := toNodeDetail(*node, pods, eventList, NodeAllocatedResources(allocatedResources)) - return &nodeDetails, nil -} - -func getNodePods(client *kubernetes.Clientset, node v1.Node) (*v1.PodList, error) { - fieldSelector, err := fields.ParseSelector("spec.nodeName=" + node.Name + - ",status.phase!=" + string(v1.PodSucceeded) + - ",status.phase!=" + string(v1.PodFailed)) - - if err != nil { - return nil, err - } - - return client.CoreV1().Pods(v1.NamespaceAll).List(context.TODO(), metaV1.ListOptions{ - FieldSelector: fieldSelector.String(), - }) -} - -func getNodeAllocatedResources(node v1.Node, podList *v1.PodList) (k8s.NodeAllocatedResources, error) { - reqs, limits := map[v1.ResourceName]resource.Quantity{}, map[v1.ResourceName]resource.Quantity{} - - for _, pod := range podList.Items { - podReqs, podLimits, err := PodRequestsAndLimits(&pod) - if err != nil { - return k8s.NodeAllocatedResources{}, err - } - for podReqName, podReqValue := range podReqs { - if value, ok := reqs[podReqName]; !ok { - reqs[podReqName] = podReqValue.DeepCopy() - } else { - value.Add(podReqValue) - reqs[podReqName] = value - } - } - for podLimitName, podLimitValue := range podLimits { - if value, ok := limits[podLimitName]; !ok { - limits[podLimitName] = podLimitValue.DeepCopy() - } else { - value.Add(podLimitValue) - limits[podLimitName] = value - } - } - } - - cpuRequests, cpuLimits, memoryRequests, memoryLimits := reqs[v1.ResourceCPU], limits[v1.ResourceCPU], reqs[v1.ResourceMemory], limits[v1.ResourceMemory] - - var cpuRequestsFraction, cpuLimitsFraction float64 = 0, 0 - if capacity := float64(node.Status.Allocatable.Cpu().MilliValue()); capacity > 0 { - cpuRequestsFraction = float64(cpuRequests.MilliValue()) / capacity * 100 - cpuLimitsFraction = float64(cpuLimits.MilliValue()) / capacity * 100 - } - - var memoryRequestsFraction, memoryLimitsFraction float64 = 0, 0 - if capacity := float64(node.Status.Allocatable.Memory().MilliValue()); capacity > 0 { - memoryRequestsFraction = float64(memoryRequests.MilliValue()) / capacity * 100 - memoryLimitsFraction = float64(memoryLimits.MilliValue()) / capacity * 100 - } - - var podFraction float64 = 0 - var podCapacity int64 = node.Status.Capacity.Pods().Value() - if podCapacity > 0 { - podFraction = float64(len(podList.Items)) / float64(podCapacity) * 100 - } - - return k8s.NodeAllocatedResources{ - CPURequests: cpuRequests.MilliValue(), - CPURequestsFraction: cpuRequestsFraction, - CPULimits: cpuLimits.MilliValue(), - CPULimitsFraction: cpuLimitsFraction, - CPUCapacity: node.Status.Allocatable.Cpu().MilliValue(), - MemoryRequests: memoryRequests.Value(), - MemoryRequestsFraction: memoryRequestsFraction, - MemoryLimits: memoryLimits.Value(), - MemoryLimitsFraction: memoryLimitsFraction, - MemoryCapacity: node.Status.Allocatable.Memory().Value(), - AllocatedPods: len(podList.Items), - PodCapacity: podCapacity, - PodFraction: podFraction, - }, nil -} - -// PodRequestsAndLimits returns a dictionary of all defined resources summed up for all -// containers of the pod. If pod overhead is non-nil, the pod overhead is added to the -// total container resource requests and to the total container limits which have a -// non-zero quantity. -func PodRequestsAndLimits(pod *v1.Pod) (reqs, limits v1.ResourceList, err error) { - reqs, limits = v1.ResourceList{}, v1.ResourceList{} - for _, container := range pod.Spec.Containers { - addResourceList(reqs, container.Resources.Requests) - addResourceList(limits, container.Resources.Limits) - } - // Init containers define the minimum of any resource - for _, container := range pod.Spec.InitContainers { - maxResourceList(reqs, container.Resources.Requests) - maxResourceList(limits, container.Resources.Limits) - } - - // Add overhead for running a pod to the sum of requests and to non-zero limits: - if pod.Spec.Overhead != nil { - addResourceList(reqs, pod.Spec.Overhead) - - for name, quantity := range pod.Spec.Overhead { - if value, ok := limits[name]; ok && !value.IsZero() { - value.Add(quantity) - limits[name] = value - } - } - } - return -} - -// addResourceList adds the resources in newList to list -func addResourceList(list, new v1.ResourceList) { - for name, quantity := range new { - if value, ok := list[name]; !ok { - list[name] = quantity.DeepCopy() - } else { - value.Add(quantity) - list[name] = value - } - } -} - -// maxResourceList sets list to the greater of list/newList for every resource -// either list -func maxResourceList(list, new v1.ResourceList) { - for name, quantity := range new { - if value, ok := list[name]; !ok { - list[name] = quantity.DeepCopy() - continue - } else { - if quantity.Cmp(value) > 0 { - list[name] = quantity.DeepCopy() - } - } - } -} - -func toNodeDetail(node v1.Node, pods *v1.PodList, eventList *v1.EventList, allocatedResources NodeAllocatedResources) NodeDetail { - return NodeDetail{ - Node: Node{ - ObjectMeta: k8s.NewObjectMeta(node.ObjectMeta), - TypeMeta: k8s.NewTypeMeta("node"), - AllocatedResources: k8s.NodeAllocatedResources(allocatedResources), - }, - - Phase: node.Status.Phase, - ProviderID: node.Spec.ProviderID, - PodCIDR: node.Spec.PodCIDR, - Unschedulable: node.Spec.Unschedulable, - NodeInfo: node.Status.NodeInfo, - Conditions: getNodeConditions(node), - ContainerImages: getContainerImages(node), - PodList: *pods, - EventList: *eventList, - Taints: node.Spec.Taints, - Addresses: node.Status.Addresses, - Ready: getNodeConditionStatus(node, v1.NodeReady), - NodeIP: k8s.NodeIP(getNodeIP(node)), - UID: k8s.UID(node.UID), - } -} diff --git a/apps/devops/services/k8s/parser/parser.go b/apps/devops/services/k8s/parser/parser.go deleted file mode 100644 index 2fb52d1..0000000 --- a/apps/devops/services/k8s/parser/parser.go +++ /dev/null @@ -1,68 +0,0 @@ -package parser - -import ( - "github.com/gin-gonic/gin" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" - "strconv" - "strings" -) - -func parsePaginationPathParameter(request *gin.Context) *dataselect.PaginationQuery { - itemsPerPage, err := strconv.ParseInt(request.Query("itemsPerPage"), 10, 0) - if err != nil { - return dataselect.NoPagination - } - - page, err := strconv.ParseInt(request.Query("page"), 10, 0) - if err != nil { - return dataselect.NoPagination - } - - // Frontend pages start from 1 and backend starts from 0 - return dataselect.NewPaginationQuery(int(itemsPerPage), int(page-1)) -} - -func parseFilterPathParameter(request *gin.Context) *dataselect.FilterQuery { - return dataselect.NewFilterQuery(strings.Split(request.Query("filterBy"), ",")) -} - -// Parses query parameters of the request and returns a SortQuery object -func parseSortPathParameter(request *gin.Context) *dataselect.SortQuery { - return dataselect.NewSortQuery(strings.Split(request.Query("sortBy"), ",")) -} - -// ParseDataSelectPathParameter parses query parameters of the request and returns a DataSelectQuery object -func ParseDataSelectPathParameter(request *gin.Context) *dataselect.DataSelectQuery { - paginationQuery := parsePaginationPathParameter(request) - sortQuery := parseSortPathParameter(request) - filterQuery := parseFilterPathParameter(request) - return dataselect.NewDataSelectQuery(paginationQuery, sortQuery, filterQuery) -} - -// ParseNamespacePathParameter parses namespace selector for list pages in path parameter. -// The namespace selector is a comma separated list of namespaces that are trimmed. -// No namespaces means "view all user namespaces", i.e., everything except kube-system. -func ParseNamespacePathParameter(request *gin.Context) *k8scommon.NamespaceQuery { - namespace := request.Query("namespace") - namespaces := strings.Split(namespace, ",") - var nonEmptyNamespaces []string - for _, n := range namespaces { - n = strings.Trim(n, " ") - if len(n) > 0 { - nonEmptyNamespaces = append(nonEmptyNamespaces, n) - } - } - return k8scommon.NewNamespaceQuery(nonEmptyNamespaces) -} - -// ParseNamespaceParameter 从URL解析命名空间 -func ParseNamespaceParameter(request *gin.Context) string { - return request.Query("namespace") - -} - -// ParseNameParameter 从URL解析name参数 -func ParseNameParameter(request *gin.Context) string { - return request.Query("name") -} diff --git a/apps/devops/services/k8s/pods/events.go b/apps/devops/services/k8s/pods/events.go deleted file mode 100644 index bebe997..0000000 --- a/apps/devops/services/k8s/pods/events.go +++ /dev/null @@ -1,13 +0,0 @@ -package pods - -import ( - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" - "pandax/apps/devops/services/k8s/event" -) - -// GetEventsForPod gets events that are associated with this pod. -func GetEventsForPod(client *kubernetes.Clientset, dsQuery *dataselect.DataSelectQuery, namespace, podName string) (*common.EventList, error) { - return event.GetResourceEvents(client, dsQuery, namespace, podName) -} diff --git a/apps/devops/services/k8s/pods/fieldpath.go b/apps/devops/services/k8s/pods/fieldpath.go deleted file mode 100644 index 3371b06..0000000 --- a/apps/devops/services/k8s/pods/fieldpath.go +++ /dev/null @@ -1,41 +0,0 @@ -package pods - -import ( - "fmt" - "strings" - - "k8s.io/apimachinery/pkg/api/meta" -) - -// FormatMap formats map[string]string to a string. -func FormatMap(m map[string]string) (fmtStr string) { - for key, value := range m { - fmtStr += fmt.Sprintf("%v=%q\n", key, value) - } - fmtStr = strings.TrimSuffix(fmtStr, "\n") - - return -} - -// ExtractFieldPathAsString extracts the field from the given object -// and returns it as a string. The object must be a pointer to an -// API type. -func ExtractFieldPathAsString(obj interface{}, fieldPath string) (string, error) { - accessor, err := meta.Accessor(obj) - if err != nil { - return "", nil - } - - switch fieldPath { - case "metadata.annotations": - return FormatMap(accessor.GetAnnotations()), nil - case "metadata.labels": - return FormatMap(accessor.GetLabels()), nil - case "metadata.name": - return accessor.GetName(), nil - case "metadata.namespace": - return accessor.GetNamespace(), nil - } - - return "", fmt.Errorf("unsupported fieldPath: %v", fieldPath) -} diff --git a/apps/devops/services/k8s/pods/logs.go b/apps/devops/services/k8s/pods/logs.go deleted file mode 100644 index b2c3880..0000000 --- a/apps/devops/services/k8s/pods/logs.go +++ /dev/null @@ -1,147 +0,0 @@ -package pods - -import ( - "context" - "io" - v1 "k8s.io/api/core/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/kubernetes/scheme" - "pandax/apps/devops/services/k8s/logs" -) - -// maximum number of lines loaded from the apiserver -var lineReadLimit int64 = 5000 - -// maximum number of bytes loaded from the apiserver -var byteReadLimit int64 = 500000 - -// PodContainerList is a list of containers of a pod. -type PodContainerList struct { - Containers []string `json:"containers"` -} - -// GetPodContainers returns containers that a pod has. -func GetPodContainers(client kubernetes.Interface, namespace, podID string) (*PodContainerList, error) { - pod, err := client.CoreV1().Pods(namespace).Get(context.TODO(), podID, metaV1.GetOptions{}) - if err != nil { - return nil, err - } - - containers := &PodContainerList{Containers: make([]string, 0)} - - for _, container := range pod.Spec.Containers { - containers.Containers = append(containers.Containers, container.Name) - } - - return containers, nil -} - -// GetLogDetails returns logs for particular pod and container. When container is null, logs for the first one -// are returned. Previous indicates to read archived logs created by log rotation or container crash -func GetLogDetails(client kubernetes.Interface, namespace, podID string, container string, - logSelector *logs.Selection, usePreviousLogs bool) (*logs.LogDetails, error) { - pod, err := client.CoreV1().Pods(namespace).Get(context.TODO(), podID, metaV1.GetOptions{}) - if err != nil { - return nil, err - } - - if len(container) == 0 { - container = pod.Spec.Containers[0].Name - } - - logOptions := mapToLogOptions(container, logSelector, usePreviousLogs) - rawLogs, err := readRawLogs(client, namespace, podID, logOptions) - if err != nil { - return nil, err - } - details := ConstructLogDetails(podID, rawLogs, container, logSelector) - return details, nil -} - -// Maps the log selection to the corresponding api object -// Read limits are set to avoid out of memory issues -func mapToLogOptions(container string, logSelector *logs.Selection, previous bool) *v1.PodLogOptions { - logOptions := &v1.PodLogOptions{ - Container: container, - Follow: false, - Previous: previous, - Timestamps: true, - } - - if logSelector.LogFilePosition == logs.Beginning { - logOptions.LimitBytes = &byteReadLimit - } else { - logOptions.TailLines = &lineReadLimit - } - - return logOptions -} - -// Construct a request for getting the logs for a pod and retrieves the logs. -func readRawLogs(client kubernetes.Interface, namespace, podID string, logOptions *v1.PodLogOptions) ( - string, error) { - readCloser, err := openStream(client, namespace, podID, logOptions) - if err != nil { - return err.Error(), nil - } - - defer readCloser.Close() - - result, err := io.ReadAll(readCloser) - if err != nil { - return "", err - } - - return string(result), nil -} - -// GetLogFile returns a stream to the log file which can be piped directly to the response. This avoids out of memory -// issues. Previous indicates to read archived logs created by log rotation or container crash -func GetLogFile(client kubernetes.Interface, namespace, podID string, container string, opts *v1.PodLogOptions) (io.ReadCloser, error) { - logOptions := &v1.PodLogOptions{ - Container: container, - Follow: false, - Previous: opts.Previous, - Timestamps: opts.Timestamps, - } - logStream, err := openStream(client, namespace, podID, logOptions) - return logStream, err -} - -func openStream(client kubernetes.Interface, namespace, podID string, logOptions *v1.PodLogOptions) (io.ReadCloser, error) { - return client.CoreV1().RESTClient().Get(). - Namespace(namespace). - Name(podID). - Resource("pods"). - SubResource("log"). - VersionedParams(logOptions, scheme.ParameterCodec).Stream(context.TODO()) -} - -// ConstructLogDetails creates a new log details structure for given parameters. -func ConstructLogDetails(podID string, rawLogs string, container string, logSelector *logs.Selection) *logs.LogDetails { - parsedLines := logs.ToLogLines(rawLogs) - logLines, fromDate, toDate, logSelection, lastPage := parsedLines.SelectLogs(logSelector) - - readLimitReached := isReadLimitReached(int64(len(rawLogs)), int64(len(parsedLines)), logSelector.LogFilePosition) - truncated := readLimitReached && lastPage - - info := logs.LogInfo{ - PodName: podID, - ContainerName: container, - FromDate: fromDate, - ToDate: toDate, - Truncated: truncated, - } - return &logs.LogDetails{ - Info: info, - Selection: logSelection, - LogLines: logLines, - } -} - -// Checks if the amount of log file returned from the apiserver is equal to the read limits -func isReadLimitReached(bytesLoaded int64, linesLoaded int64, logFilePosition string) bool { - return (logFilePosition == logs.Beginning && bytesLoaded >= byteReadLimit) || - (logFilePosition == logs.End && linesLoaded >= lineReadLimit) -} diff --git a/apps/devops/services/k8s/pods/pod_common.go b/apps/devops/services/k8s/pods/pod_common.go deleted file mode 100644 index 9e7d5f4..0000000 --- a/apps/devops/services/k8s/pods/pod_common.go +++ /dev/null @@ -1,232 +0,0 @@ -package pods - -import ( - "fmt" - v1 "k8s.io/api/core/v1" - meta "k8s.io/apimachinery/pkg/apis/meta/v1" - "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" - "pandax/apps/devops/services/k8s/event" -) - -// getPodStatusPhase returns one of four pod status phases (Pending, Running, Succeeded, Failed, Unknown, Terminating) -func getPodStatusPhase(pod v1.Pod, warnings []common.Event) v1.PodPhase { - // For terminated pods that failed - if pod.Status.Phase == v1.PodFailed { - return v1.PodFailed - } - - // For successfully terminated pods - if pod.Status.Phase == v1.PodSucceeded { - return v1.PodSucceeded - } - - ready := false - initialized := false - for _, c := range pod.Status.Conditions { - if c.Type == v1.PodReady { - ready = c.Status == v1.ConditionTrue - } - if c.Type == v1.PodInitialized { - initialized = c.Status == v1.ConditionTrue - } - } - - if initialized && ready && pod.Status.Phase == v1.PodRunning { - return v1.PodRunning - } - - // If the pod would otherwise be pending but has warning then label it as - // failed and show and error to the user. - if len(warnings) > 0 { - return v1.PodFailed - } - - if pod.DeletionTimestamp != nil && pod.Status.Reason == "NodeLost" { - return v1.PodUnknown - } else if pod.DeletionTimestamp != nil { - return "Terminating" - } - - // pending - return v1.PodPending -} - -type PodCell v1.Pod - -func (self PodCell) GetProperty(name dataselect.PropertyName) dataselect.ComparableValue { - switch name { - case dataselect.NameProperty: - return dataselect.StdComparableString(self.ObjectMeta.Name) - case dataselect.StatusProperty: - return dataselect.StdComparableString(getPodStatus(v1.Pod(self))) - case dataselect.CreationTimestampProperty: - return dataselect.StdComparableTime(self.ObjectMeta.CreationTimestamp.Time) - case dataselect.NamespaceProperty: - return dataselect.StdComparableString(self.ObjectMeta.Namespace) - default: - // if name is not supported then just return a constant dummy value, sort will have no effect. - return nil - } -} - -// getPodStatus returns status string calculated based on the same logic as kubectl -// Base code: https://github.com/kubernetes/kubernetes/blob/master/pkg/printers/internalversion/printers.go#L734 -func getPodStatus(pod v1.Pod) string { - restarts := 0 - readyContainers := 0 - - reason := string(pod.Status.Phase) - if pod.Status.Reason != "" { - reason = pod.Status.Reason - } - - initializing := false - for i := range pod.Status.InitContainerStatuses { - container := pod.Status.InitContainerStatuses[i] - restarts += int(container.RestartCount) - switch { - case container.State.Terminated != nil && container.State.Terminated.ExitCode == 0: - continue - case container.State.Terminated != nil: - // initialization is failed - if len(container.State.Terminated.Reason) == 0 { - if container.State.Terminated.Signal != 0 { - reason = fmt.Sprintf("Init: Signal %d", container.State.Terminated.Signal) - } else { - reason = fmt.Sprintf("Init: ExitCode %d", container.State.Terminated.ExitCode) - } - } else { - reason = "Init:" + container.State.Terminated.Reason - } - initializing = true - case container.State.Waiting != nil && len(container.State.Waiting.Reason) > 0 && container.State.Waiting.Reason != "PodInitializing": - reason = fmt.Sprintf("Init: %s", container.State.Waiting.Reason) - initializing = true - default: - reason = fmt.Sprintf("Init: %d/%d", i, len(pod.Spec.InitContainers)) - initializing = true - } - break - } - if !initializing { - restarts = 0 - hasRunning := false - for i := len(pod.Status.ContainerStatuses) - 1; i >= 0; i-- { - container := pod.Status.ContainerStatuses[i] - - restarts += int(container.RestartCount) - if container.State.Waiting != nil && container.State.Waiting.Reason != "" { - reason = container.State.Waiting.Reason - } else if container.State.Terminated != nil && container.State.Terminated.Reason != "" { - reason = container.State.Terminated.Reason - } else if container.State.Terminated != nil && container.State.Terminated.Reason == "" { - if container.State.Terminated.Signal != 0 { - reason = fmt.Sprintf("Signal: %d", container.State.Terminated.Signal) - } else { - reason = fmt.Sprintf("ExitCode: %d", container.State.Terminated.ExitCode) - } - } else if container.Ready && container.State.Running != nil { - hasRunning = true - readyContainers++ - } - } - - // change pod status back to "Running" if there is at least one container still reporting as "Running" status - if reason == "Completed" && hasRunning { - if hasPodReadyCondition(pod.Status.Conditions) { - reason = string(v1.PodRunning) - } else { - reason = "NotReady" - } - } - } - - if pod.DeletionTimestamp != nil && pod.Status.Reason == "NodeLost" { - reason = string(v1.PodUnknown) - } else if pod.DeletionTimestamp != nil { - reason = "Terminating" - } - - if len(reason) == 0 { - reason = string(v1.PodUnknown) - } - - return reason -} - -// getRestartCount return the restart count of given pod (total number of its containers restarts). -func getRestartCount(pod v1.Pod) int32 { - var restartCount int32 = 0 - for _, containerStatus := range pod.Status.ContainerStatuses { - restartCount += containerStatus.RestartCount - } - return restartCount -} - -func toCells(std []v1.Pod) []dataselect.DataCell { - cells := make([]dataselect.DataCell, len(std)) - for i := range std { - cells[i] = PodCell(std[i]) - } - return cells -} - -func fromCells(cells []dataselect.DataCell) []v1.Pod { - std := make([]v1.Pod, len(cells)) - for i := range std { - std[i] = v1.Pod(cells[i].(PodCell)) - } - return std -} - -func getStatus(list *v1.PodList, events []v1.Event) common.ResourceStatus { - info := common.ResourceStatus{} - if list == nil { - return info - } - - for _, pod := range list.Items { - warnings := event.GetPodsEventWarnings(events, []v1.Pod{pod}) - switch getPodStatusPhase(pod, warnings) { - case v1.PodFailed: - info.Failed++ - case v1.PodSucceeded: - info.Succeeded++ - case v1.PodRunning: - info.Running++ - case v1.PodPending: - info.Pending++ - case v1.PodUnknown: - info.Unknown++ - case "Terminating": - info.Terminating++ - } - } - - return info -} - -func hasPodReadyCondition(conditions []v1.PodCondition) bool { - for _, condition := range conditions { - if condition.Type == v1.PodReady && condition.Status == v1.ConditionTrue { - return true - } - } - return false -} - -func getPodConditions(pod v1.Pod) []common.Condition { - var conditions []common.Condition - for _, condition := range pod.Status.Conditions { - conditions = append(conditions, common.Condition{ - Type: string(condition.Type), - Status: meta.ConditionStatus(condition.Status), - LastProbeTime: condition.LastProbeTime, - LastTransitionTime: condition.LastTransitionTime, - Reason: condition.Reason, - Message: condition.Message, - }) - } - return conditions -} diff --git a/apps/devops/services/k8s/pods/pod_detail.go b/apps/devops/services/k8s/pods/pod_detail.go deleted file mode 100644 index 0a14867..0000000 --- a/apps/devops/services/k8s/pods/pod_detail.go +++ /dev/null @@ -1,420 +0,0 @@ -package pods - -import ( - "context" - "encoding/base64" - "fmt" - "pandax/base/global" - - v1 "k8s.io/api/core/v1" - res "k8s.io/apimachinery/pkg/api/resource" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/kubernetes" - "math" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/controller" - "pandax/apps/devops/services/k8s/dataselect" - "pandax/apps/devops/services/k8s/pvc" - "strconv" -) - -// PodDetail is a presentation layer view of Kubernetes Pod resource. -type PodDetail struct { - ObjectMeta k8s.ObjectMeta `json:"objectMeta"` - TypeMeta k8s.TypeMeta `json:"typeMeta"` - PodPhase string `json:"podPhase"` - PodIP string `json:"podIP"` - NodeName string `json:"nodeName"` - ServiceAccountName string `json:"serviceAccountName"` - RestartCount int32 `json:"restartCount"` - QOSClass string `json:"qosClass"` - Controller *controller.ResourceOwner `json:"controller,omitempty"` - Containers []Container `json:"containers"` - InitContainers []Container `json:"initContainers"` - Conditions []k8scommon.Condition `json:"conditions"` - ImagePullSecrets []v1.LocalObjectReference `json:"imagePullSecrets,omitempty"` - EventList k8scommon.EventList `json:"eventList"` - PersistentvolumeclaimList pvc.PersistentVolumeClaimList `json:"persistentVolumeClaimList"` - SecurityContext *v1.PodSecurityContext `json:"securityContext"` -} - -// Container represents a docker/rkt/etc. container that lives in a pod. -type Container struct { - // Name of the container. - Name string `json:"name"` - - // Image URI of the container. - Image string `json:"image"` - - // Ports of the container - Ports []v1.ContainerPort `json:"ports"` - - // List of environment variables. - Env []EnvVar `json:"env"` - - // Commands of the container - Commands []string `json:"commands"` - - // Command arguments - Args []string `json:"args"` - - // Information about mounted volumes - VolumeMounts []VolumeMount `json:"volumeMounts"` - - // Security configuration that will be applied to a container. - SecurityContext *v1.SecurityContext `json:"securityContext"` - - // Status of a pod container - Status *v1.ContainerStatus `json:"status"` - - // Resource of a pod limit requests cpu mem - Resources v1.ResourceRequirements `json:"resource"` - // Probes - LivenessProbe *v1.Probe `json:"livenessProbe"` - ReadinessProbe *v1.Probe `json:"readinessProbe"` - StartupProbe *v1.Probe `json:"startupProbe"` - Lifecycle *v1.Lifecycle `json:"lifecycle"` - // ImagePullPolicy of a pod - ImagePullPolicy v1.PullPolicy `json:"imagePullPolicy"` -} - -// EnvVar represents an environment variable of a container. -type EnvVar struct { - // Name of the variable. - Name string `json:"name"` - - // Value of the variable. May be empty if value from is defined. - Value string `json:"value"` - - // Defined for derived variables. If non-null, the value is get from the reference. - // Note that this is an API struct. This is intentional, as EnvVarSources are plain struct - // references. - ValueFrom *v1.EnvVarSource `json:"valueFrom"` -} - -type VolumeMount struct { - // Name of the variable. - Name string `json:"name"` - - // Is the volume read only ? - ReadOnly bool `json:"readOnly"` - - // Path within the container at which the volume should be mounted. Must not contain ':'. - MountPath string `json:"mountPath"` - - // Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root). - SubPath string `json:"subPath"` - - // Information about the Volume itself - Volume v1.Volume `json:"volume"` -} - -// GetPodDetail returns the details of a named Pod from a particular namespace. -func GetPodDetail(client *kubernetes.Clientset, namespace, name string) (*PodDetail, error) { - global.Log.Info(fmt.Sprintf("Getting details of %s pod in %s namespace", name, namespace)) - - channels := &k8scommon.ResourceChannels{ - ConfigMapList: k8scommon.GetConfigMapListChannel(client, k8scommon.NewSameNamespaceQuery(namespace), 1), - SecretList: k8scommon.GetSecretListChannel(client, k8scommon.NewSameNamespaceQuery(namespace), 1), - } - - pod, err := client.CoreV1().Pods(namespace).Get(context.TODO(), name, metaV1.GetOptions{}) - if err != nil { - return nil, err - } - - podController, err := getPodController(client, k8scommon.NewSameNamespaceQuery(namespace), pod) - if err != nil { - return nil, err - } - - configMapList := <-channels.ConfigMapList.List - err = <-channels.ConfigMapList.Error - if err != nil { - return nil, err - } - - secretList := <-channels.SecretList.List - err = <-channels.SecretList.Error - if err != nil { - return nil, err - } - - eventList, err := GetEventsForPod(client, dataselect.DefaultDataSelect, pod.Namespace, pod.Name) - if err != nil { - return nil, err - } - - persistentVolumeClaimList, err := pvc.GetPodPersistentVolumeClaims(client, namespace, name, dataselect.DefaultDataSelect) - if err != nil { - return nil, err - } - - podDetail := toPodDetail(pod, configMapList, secretList, podController, eventList, persistentVolumeClaimList) - return &podDetail, nil -} - -func getPodController(client *kubernetes.Clientset, nsQuery *k8scommon.NamespaceQuery, pod *v1.Pod) (*controller.ResourceOwner, error) { - channels := &k8scommon.ResourceChannels{ - PodList: k8scommon.GetPodListChannel(client, nsQuery, 1), - EventList: k8scommon.GetEventListChannel(client, nsQuery, 1), - } - - pods := <-channels.PodList.List - err := <-channels.PodList.Error - if err != nil { - return nil, err - } - - events := <-channels.EventList.List - if err := <-channels.EventList.Error; err != nil { - events = &v1.EventList{} - } - - var ctrl controller.ResourceOwner - ownerRef := metaV1.GetControllerOf(pod) - if ownerRef != nil { - var rc controller.ResourceController - rc, err = controller.NewResourceController(*ownerRef, pod.Namespace, client) - if err == nil { - ctrl = rc.Get(pods.Items, events.Items) - } - } - - return &ctrl, nil -} - -func toPodDetail(pod *v1.Pod, configMaps *v1.ConfigMapList, secrets *v1.SecretList, controller *controller.ResourceOwner, - events *k8scommon.EventList, persistentVolumeClaimList *pvc.PersistentVolumeClaimList) PodDetail { - return PodDetail{ - ObjectMeta: k8s.NewObjectMeta(pod.ObjectMeta), - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindPod), - PodPhase: getPodStatus(*pod), - PodIP: pod.Status.PodIP, - RestartCount: getRestartCount(*pod), - QOSClass: string(pod.Status.QOSClass), - NodeName: pod.Spec.NodeName, - ServiceAccountName: pod.Spec.ServiceAccountName, - Controller: controller, - Containers: extractContainerInfo(pod.Spec.Containers, pod, configMaps, secrets), - InitContainers: extractContainerInfo(pod.Spec.InitContainers, pod, configMaps, secrets), - Conditions: getPodConditions(*pod), - ImagePullSecrets: pod.Spec.ImagePullSecrets, - EventList: *events, - PersistentvolumeclaimList: *persistentVolumeClaimList, - SecurityContext: pod.Spec.SecurityContext, - } -} - -func extractContainerInfo(containerList []v1.Container, pod *v1.Pod, configMaps *v1.ConfigMapList, secrets *v1.SecretList) []Container { - containers := make([]Container, 0) - for _, container := range containerList { - vars := make([]EnvVar, 0) - for _, envVar := range container.Env { - variable := EnvVar{ - Name: envVar.Name, - Value: envVar.Value, - ValueFrom: envVar.ValueFrom, - } - if variable.ValueFrom != nil { - variable.Value = evalValueFrom(variable.ValueFrom, &container, pod, - configMaps, secrets) - } - vars = append(vars, variable) - } - vars = append(vars, evalEnvFrom(container, configMaps, secrets)...) - - volume_mounts := extractContainerMounts(container, pod) - - containers = append(containers, Container{ - Name: container.Name, - Image: container.Image, - Ports: container.Ports, - Resources: container.Resources, - Env: vars, - Commands: container.Command, - Args: container.Args, - VolumeMounts: volume_mounts, - SecurityContext: container.SecurityContext, - Status: extractContainerStatus(pod, &container), - LivenessProbe: container.LivenessProbe, - ReadinessProbe: container.ReadinessProbe, - StartupProbe: container.StartupProbe, - Lifecycle: container.Lifecycle, - ImagePullPolicy: container.ImagePullPolicy, - }) - } - return containers -} - -func evalEnvFrom(container v1.Container, configMaps *v1.ConfigMapList, secrets *v1.SecretList) []EnvVar { - vars := make([]EnvVar, 0) - for _, envFromVar := range container.EnvFrom { - switch { - case envFromVar.ConfigMapRef != nil: - name := envFromVar.ConfigMapRef.LocalObjectReference.Name - for _, configMap := range configMaps.Items { - if configMap.ObjectMeta.Name == name { - for key, value := range configMap.Data { - valueFrom := &v1.EnvVarSource{ - ConfigMapKeyRef: &v1.ConfigMapKeySelector{ - LocalObjectReference: v1.LocalObjectReference{ - Name: name, - }, - Key: key, - }, - } - variable := EnvVar{ - Name: envFromVar.Prefix + key, - Value: value, - ValueFrom: valueFrom, - } - vars = append(vars, variable) - } - break - } - } - case envFromVar.SecretRef != nil: - name := envFromVar.SecretRef.LocalObjectReference.Name - for _, secret := range secrets.Items { - if secret.ObjectMeta.Name == name { - for key, value := range secret.Data { - valueFrom := &v1.EnvVarSource{ - SecretKeyRef: &v1.SecretKeySelector{ - LocalObjectReference: v1.LocalObjectReference{ - Name: name, - }, - Key: key, - }, - } - variable := EnvVar{ - Name: envFromVar.Prefix + key, - Value: base64.StdEncoding.EncodeToString(value), - ValueFrom: valueFrom, - } - vars = append(vars, variable) - } - break - } - } - } - } - return vars -} - -// evalValueFrom evaluates environment value from given source. For more details check: -// https://github.com/kubernetes/kubernetes/blob/d82e51edc5f02bff39661203c9b503d054c3493b/pkg/kubectl/describe.go#L1056 -func evalValueFrom(src *v1.EnvVarSource, container *v1.Container, pod *v1.Pod, configMaps *v1.ConfigMapList, secrets *v1.SecretList) string { - switch { - case src.ConfigMapKeyRef != nil: - name := src.ConfigMapKeyRef.LocalObjectReference.Name - for _, configMap := range configMaps.Items { - if configMap.ObjectMeta.Name == name { - return configMap.Data[src.ConfigMapKeyRef.Key] - } - } - case src.SecretKeyRef != nil: - name := src.SecretKeyRef.LocalObjectReference.Name - for _, secret := range secrets.Items { - if secret.ObjectMeta.Name == name { - return base64.StdEncoding.EncodeToString([]byte( - secret.Data[src.SecretKeyRef.Key])) - } - } - case src.ResourceFieldRef != nil: - valueFrom, err := extractContainerResourceValue(src.ResourceFieldRef, container) - if err != nil { - valueFrom = "" - } - resource := src.ResourceFieldRef.Resource - if valueFrom == "0" && (resource == "limits.cpu" || resource == "limits.memory") { - valueFrom = "node allocatable" - } - return valueFrom - case src.FieldRef != nil: - gv, err := schema.ParseGroupVersion(src.FieldRef.APIVersion) - if err != nil { - global.Log.Warn(err.Error()) - return "" - } - gvk := gv.WithKind("Pod") - internalFieldPath, _, err := runtime.NewScheme().ConvertFieldLabel(gvk, src.FieldRef.FieldPath, "") - if err != nil { - global.Log.Warn(err.Error()) - return "" - } - valueFrom, err := ExtractFieldPathAsString(pod, internalFieldPath) - if err != nil { - global.Log.Warn(err.Error()) - return "" - } - return valueFrom - } - return "" -} - -func extractContainerMounts(container v1.Container, pod *v1.Pod) []VolumeMount { - volume_mounts := make([]VolumeMount, 0) - for _, a_volume_mount := range container.VolumeMounts { - volume_mount := VolumeMount{ - Name: a_volume_mount.Name, - ReadOnly: a_volume_mount.ReadOnly, - MountPath: a_volume_mount.MountPath, - SubPath: a_volume_mount.SubPath, - Volume: getVolume(pod.Spec.Volumes, a_volume_mount.Name), - } - volume_mounts = append(volume_mounts, volume_mount) - } - return volume_mounts -} - -func extractContainerStatus(pod *v1.Pod, container *v1.Container) *v1.ContainerStatus { - for _, status := range pod.Status.ContainerStatuses { - if status.Name == container.Name { - return &status - } - } - - return nil -} - -// extractContainerResourceValue extracts the value of a resource in an already known container. -func extractContainerResourceValue(fs *v1.ResourceFieldSelector, container *v1.Container) (string, - error) { - divisor := res.Quantity{} - if divisor.Cmp(fs.Divisor) == 0 { - divisor = res.MustParse("1") - } else { - divisor = fs.Divisor - } - - switch fs.Resource { - case "limits.cpu": - return strconv.FormatInt(int64(math.Ceil(float64(container.Resources.Limits. - Cpu().MilliValue())/float64(divisor.MilliValue()))), 10), nil - case "limits.memory": - return strconv.FormatInt(int64(math.Ceil(float64(container.Resources.Limits. - Memory().Value())/float64(divisor.Value()))), 10), nil - case "requests.cpu": - return strconv.FormatInt(int64(math.Ceil(float64(container.Resources.Requests. - Cpu().MilliValue())/float64(divisor.MilliValue()))), 10), nil - case "requests.memory": - return strconv.FormatInt(int64(math.Ceil(float64(container.Resources.Requests. - Memory().Value())/float64(divisor.Value()))), 10), nil - } - - return "", fmt.Errorf("Unsupported container resource : %v", fs.Resource) -} - -func getVolume(volumes []v1.Volume, volumeName string) v1.Volume { - for _, volume := range volumes { - if volume.Name == volumeName { - // yes, this is exponential, but N is VERY small, so the malloc for creating a named dictionary would probably take longer - return volume - } - } - return v1.Volume{} -} diff --git a/apps/devops/services/k8s/pods/pods.go b/apps/devops/services/k8s/pods/pods.go deleted file mode 100644 index 6ae26e3..0000000 --- a/apps/devops/services/k8s/pods/pods.go +++ /dev/null @@ -1,155 +0,0 @@ -package pods - -import ( - "context" - "fmt" - "pandax/base/global" - - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" - "pandax/apps/devops/services/k8s/event" -) - -// PodList contains a list of Pods in the cluster. -type PodList struct { - ListMeta k8s.ListMeta `json:"listMeta"` - - // Basic information about resources status on the list. - Status k8scommon.ResourceStatus `json:"status"` - - // Unordered list of Pods. - Pods []Pod `json:"pods"` -} - -type PodStatus struct { - Status string `json:"status"` - PodPhase v1.PodPhase `json:"podPhase"` - ContainerStates []v1.ContainerState `json:"containerStates"` -} - -// Pod is a presentation layer view of Kubernetes Pod resource. This means it is Pod plus additional augmented data -// we can get from other sources (like services that target it). -type Pod struct { - ObjectMeta k8s.ObjectMeta `json:"objectMeta"` - TypeMeta k8s.TypeMeta `json:"typeMeta"` - - // Status determined based on the same logic as kubectl. - Status string `json:"status"` - - // RestartCount of containers restarts. - RestartCount int32 `json:"restartCount"` - - // Pod warning events - Warnings []k8scommon.Event `json:"warnings"` - - // NodeName of the Node this Pod runs on. - NodeName string `json:"nodeName"` - - // ContainerImages holds a list of the Pod images. - ContainerImages []string `json:"containerImages"` - - // Pod ip address - PodIP string `json:"podIP"` -} - -var EmptyPodList = &PodList{ - Pods: make([]Pod, 0), - ListMeta: k8s.ListMeta{ - TotalItems: 0, - }, -} - -func GetPodsList(client *kubernetes.Clientset, nsQuery *k8scommon.NamespaceQuery, dsQuery *dataselect.DataSelectQuery) (*PodList, error) { - global.Log.Info("Getting list of all pods in the cluster") - channels := &k8scommon.ResourceChannels{ - PodList: k8scommon.GetPodListChannelWithOptions(client, nsQuery, metav1.ListOptions{}, 1), - EventList: k8scommon.GetEventListChannel(client, nsQuery, 1), - } - - return GetPodListFromChannels(channels, dsQuery) - -} - -// GetPodListFromChannels returns a list of all Pods in the cluster -// reading required resource list once from the channels. -func GetPodListFromChannels(channels *k8scommon.ResourceChannels, dsQuery *dataselect.DataSelectQuery) (*PodList, error) { - - pods := <-channels.PodList.List - err := <-channels.PodList.Error - if err != nil { - return nil, err - } - - eventList := <-channels.EventList.List - err = <-channels.EventList.Error - if err != nil { - return nil, err - } - - podList := ToPodList(pods.Items, eventList.Items, dsQuery) - podList.Status = getStatus(pods, eventList.Items) - return &podList, nil -} -func ToPodList(pods []v1.Pod, events []v1.Event, dsQuery *dataselect.DataSelectQuery) PodList { - podList := PodList{ - Pods: make([]Pod, 0), - } - - podCells, filteredTotal := dataselect.GenericDataSelectWithFilter(toCells(pods), dsQuery) - pods = fromCells(podCells) - podList.ListMeta = k8s.ListMeta{TotalItems: filteredTotal} - - for _, pod := range pods { - warnings := event.GetPodsEventWarnings(events, []v1.Pod{pod}) - podDetail := ToPod(&pod, warnings) - podList.Pods = append(podList.Pods, podDetail) - } - - return podList -} - -func ToPod(pod *v1.Pod, warnings []k8scommon.Event) Pod { - podDetail := Pod{ - ObjectMeta: k8s.NewObjectMeta(pod.ObjectMeta), - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindPod), - Warnings: warnings, - Status: getPodStatus(*pod), - RestartCount: getRestartCount(*pod), - NodeName: pod.Spec.NodeName, - ContainerImages: k8scommon.GetContainerImages(&pod.Spec), - PodIP: pod.Status.PodIP, - } - - return podDetail -} - -func DeleteCollectionPods(client *kubernetes.Clientset, podList []k8s.RemovePodsData) (err error) { - global.Log.Info("批量删除容器组开始") - for _, v := range podList { - global.Log.Info(fmt.Sprintf("delete pods:%v, ns: %v", v.PodName, v.Namespace)) - err := client.CoreV1().Pods(v.Namespace).Delete( - context.TODO(), - v.PodName, - metav1.DeleteOptions{}, - ) - if err != nil { - global.Log.Error(err.Error()) - return err - } - } - global.Log.Info("删除容器组已完成") - return nil -} - -func DeletePod(client *kubernetes.Clientset, namespace string, name string) (err error) { - global.Log.Info(fmt.Sprintf("请求删除单个pod:%v, namespace: %v", name, namespace)) - return client.CoreV1().Pods(namespace).Delete( - context.TODO(), - name, - metav1.DeleteOptions{}, - ) -} diff --git a/apps/devops/services/k8s/pv/pv.go b/apps/devops/services/k8s/pv/pv.go deleted file mode 100644 index 94b35b4..0000000 --- a/apps/devops/services/k8s/pv/pv.go +++ /dev/null @@ -1,94 +0,0 @@ -package pv - -import ( - "context" - "fmt" - "pandax/base/global" - - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" -) - -// PersistentVolumeList contains a list of Persistent Volumes in the cluster. -type PersistentVolumeList struct { - ListMeta k8s.ListMeta `json:"listMeta"` - Items []PersistentVolume `json:"items"` -} - -// PersistentVolume provides the simplified presentation layer view of Kubernetes Persistent Volume resource. -type PersistentVolume struct { - ObjectMeta k8s.ObjectMeta `json:"objectMeta"` - TypeMeta k8s.TypeMeta `json:"typeMeta"` - Capacity v1.ResourceList `json:"capacity"` - AccessModes []v1.PersistentVolumeAccessMode `json:"accessModes"` - ReclaimPolicy v1.PersistentVolumeReclaimPolicy `json:"reclaimPolicy"` - StorageClass string `json:"storageClass"` - MountOptions []string `json:"mountOptions"` - Status v1.PersistentVolumePhase `json:"status"` - Claim string `json:"claim"` - Reason string `json:"reason"` -} - -// GetPersistentVolumeList returns a list of all Persistent Volumes in the cluster. -func GetPersistentVolumeList(client kubernetes.Interface, dsQuery *dataselect.DataSelectQuery) (*PersistentVolumeList, error) { - global.Log.Info("Getting list persistent volumes") - channels := &k8scommon.ResourceChannels{ - PersistentVolumeList: k8scommon.GetPersistentVolumeListChannel(client, 1), - } - - return GetPersistentVolumeListFromChannels(channels, dsQuery) -} - -// GetPersistentVolumeListFromChannels returns a list of all Persistent Volumes in the cluster -// reading required resource list once from the channels. -func GetPersistentVolumeListFromChannels(channels *k8scommon.ResourceChannels, dsQuery *dataselect.DataSelectQuery) (*PersistentVolumeList, error) { - persistentVolumes := <-channels.PersistentVolumeList.List - err := <-channels.PersistentVolumeList.Error - if err != nil { - return nil, err - } - - return toPersistentVolumeList(persistentVolumes.Items, dsQuery), nil -} - -func toPersistentVolumeList(persistentVolumes []v1.PersistentVolume, dsQuery *dataselect.DataSelectQuery) *PersistentVolumeList { - - result := &PersistentVolumeList{ - Items: make([]PersistentVolume, 0), - ListMeta: k8s.ListMeta{TotalItems: len(persistentVolumes)}, - } - - pvCells, filteredTotal := dataselect.GenericDataSelectWithFilter(toCells(persistentVolumes), dsQuery) - persistentVolumes = fromCells(pvCells) - result.ListMeta = k8s.ListMeta{TotalItems: filteredTotal} - - for _, item := range persistentVolumes { - result.Items = append(result.Items, toPersistentVolume(item)) - } - - return result -} - -func toPersistentVolume(pv v1.PersistentVolume) PersistentVolume { - return PersistentVolume{ - ObjectMeta: k8s.NewObjectMeta(pv.ObjectMeta), - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindPersistentVolume), - Capacity: pv.Spec.Capacity, - AccessModes: pv.Spec.AccessModes, - ReclaimPolicy: pv.Spec.PersistentVolumeReclaimPolicy, - StorageClass: pv.Spec.StorageClassName, - MountOptions: pv.Spec.MountOptions, - Status: pv.Status.Phase, - Claim: getPersistentVolumeClaim(&pv), - Reason: pv.Status.Reason, - } -} - -func DeletePersistentVolume(client *kubernetes.Clientset, name string) (err error) { - global.Log.Info(fmt.Sprintf("Start deleting persistent volume, name: %v", name)) - return client.CoreV1().PersistentVolumes().Delete(context.TODO(), name, metav1.DeleteOptions{}) -} diff --git a/apps/devops/services/k8s/pv/pv_common.go b/apps/devops/services/k8s/pv/pv_common.go deleted file mode 100644 index d9633e6..0000000 --- a/apps/devops/services/k8s/pv/pv_common.go +++ /dev/null @@ -1,95 +0,0 @@ -package pv - -import ( - "context" - "fmt" - "pandax/base/global" - - v1 "k8s.io/api/core/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - client "k8s.io/client-go/kubernetes" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" - "strings" -) - -// GetStorageClassPersistentVolumes gets persistentvolumes that are associated with this storageclass. -func GetStorageClassPersistentVolumes(client client.Interface, storageClassName string, - dsQuery *dataselect.DataSelectQuery) (*PersistentVolumeList, error) { - - storageClass, err := client.StorageV1().StorageClasses().Get(context.TODO(), storageClassName, metaV1.GetOptions{}) - - if err != nil { - return nil, err - } - - channels := &k8scommon.ResourceChannels{ - PersistentVolumeList: k8scommon.GetPersistentVolumeListChannel( - client, 1), - } - - persistentVolumeList := <-channels.PersistentVolumeList.List - - err = <-channels.PersistentVolumeList.Error - if err != nil { - return nil, err - } - - storagePersistentVolumes := make([]v1.PersistentVolume, 0) - for _, pv := range persistentVolumeList.Items { - if strings.Compare(pv.Spec.StorageClassName, storageClass.Name) == 0 { - storagePersistentVolumes = append(storagePersistentVolumes, pv) - } - } - - global.Log.Info(fmt.Sprintf("Found %d persistentvolumes related to %s storageclass", len(storagePersistentVolumes), storageClassName)) - - return toPersistentVolumeList(storagePersistentVolumes, dsQuery), nil -} - -// getPersistentVolumeClaim returns Persistent Volume claim using "namespace/claim" format. -func getPersistentVolumeClaim(pv *v1.PersistentVolume) string { - var claim string - - if pv.Spec.ClaimRef != nil { - claim = pv.Spec.ClaimRef.Namespace + "/" + pv.Spec.ClaimRef.Name - } - - return claim -} - -// PersistentVolumeCell allows to perform complex data section on []api.PersistentVolume. -type PersistentVolumeCell v1.PersistentVolume - -// GetProperty allows to perform complex data section on PersistentVolumeCell. -func (self PersistentVolumeCell) GetProperty(name dataselect.PropertyName) dataselect.ComparableValue { - switch name { - case dataselect.NameProperty: - return dataselect.StdComparableString(self.ObjectMeta.Name) - case dataselect.CreationTimestampProperty: - return dataselect.StdComparableTime(self.ObjectMeta.CreationTimestamp.Time) - case dataselect.NamespaceProperty: - return dataselect.StdComparableString(self.ObjectMeta.Namespace) - default: - // if name is not supported then just return a constant dummy value, sort will have no effect. - return nil - } -} - -// toCells converts []api.PersistentVolume to []dataselect.DataCell. -func toCells(std []v1.PersistentVolume) []dataselect.DataCell { - cells := make([]dataselect.DataCell, len(std)) - for i := range std { - cells[i] = PersistentVolumeCell(std[i]) - } - return cells -} - -// fromCells converts cells []dataselect.DataCell to []api.PersistentVolume. -func fromCells(cells []dataselect.DataCell) []v1.PersistentVolume { - std := make([]v1.PersistentVolume, len(cells)) - for i := range std { - std[i] = v1.PersistentVolume(cells[i].(PersistentVolumeCell)) - } - return std -} diff --git a/apps/devops/services/k8s/pv/pv_detail.go b/apps/devops/services/k8s/pv/pv_detail.go deleted file mode 100644 index dc35016..0000000 --- a/apps/devops/services/k8s/pv/pv_detail.go +++ /dev/null @@ -1,40 +0,0 @@ -package pv - -import ( - "context" - "fmt" - "pandax/base/global" - - v1 "k8s.io/api/core/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - client "k8s.io/client-go/kubernetes" -) - -// PersistentVolumeDetail provides the presentation layer view of Kubernetes Persistent Volume resource. -type PersistentVolumeDetail struct { - // Extends list item structure. - PersistentVolume `json:",inline"` - - Message string `json:"message"` - PersistentVolumeSource v1.PersistentVolumeSource `json:"persistentVolumeSource"` -} - -// GetPersistentVolumeDetail returns detailed information about a persistent volume -func GetPersistentVolumeDetail(client client.Interface, name string) (*PersistentVolumeDetail, error) { - global.Log.Info(fmt.Sprintf("Getting details of %s persistent volume", name)) - - rawPersistentVolume, err := client.CoreV1().PersistentVolumes().Get(context.TODO(), name, metaV1.GetOptions{}) - if err != nil { - return nil, err - } - - return getPersistentVolumeDetail(*rawPersistentVolume), nil -} - -func getPersistentVolumeDetail(pv v1.PersistentVolume) *PersistentVolumeDetail { - return &PersistentVolumeDetail{ - PersistentVolume: toPersistentVolume(pv), - Message: pv.Status.Message, - PersistentVolumeSource: pv.Spec.PersistentVolumeSource, - } -} diff --git a/apps/devops/services/k8s/pvc/pvc.go b/apps/devops/services/k8s/pvc/pvc.go deleted file mode 100644 index dd1537f..0000000 --- a/apps/devops/services/k8s/pvc/pvc.go +++ /dev/null @@ -1,93 +0,0 @@ -package pvc - -import ( - "context" - "fmt" - "pandax/base/global" - - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" -) - -// PersistentVolumeClaimList contains a list of Persistent Volume Claims in the cluster. -type PersistentVolumeClaimList struct { - ListMeta k8s.ListMeta `json:"listMeta"` - - // Unordered list of persistent volume claims - Items []PersistentVolumeClaim `json:"items"` -} - -// PersistentVolumeClaim provides the simplified presentation layer view of Kubernetes Persistent Volume Claim resource. -type PersistentVolumeClaim struct { - ObjectMeta k8s.ObjectMeta `json:"objectMeta"` - TypeMeta k8s.TypeMeta `json:"typeMeta"` - Status string `json:"status"` - Volume string `json:"volume"` - Capacity v1.ResourceList `json:"capacity"` - AccessModes []v1.PersistentVolumeAccessMode `json:"accessModes"` - StorageClass *string `json:"storageClass"` -} - -// GetPersistentVolumeClaimList returns a list of all Persistent Volume Claims in the cluster. -func GetPersistentVolumeClaimList(client kubernetes.Interface, nsQuery *k8scommon.NamespaceQuery, dsQuery *dataselect.DataSelectQuery) (*PersistentVolumeClaimList, error) { - - global.Log.Info("Getting list persistent volumes claims") - channels := &k8scommon.ResourceChannels{ - PersistentVolumeClaimList: k8scommon.GetPersistentVolumeClaimListChannel(client, nsQuery, 1), - } - - return GetPersistentVolumeClaimListFromChannels(channels, nsQuery, dsQuery) -} - -// GetPersistentVolumeClaimListFromChannels returns a list of all Persistent Volume Claims in the cluster -// reading required resource list once from the channels. -func GetPersistentVolumeClaimListFromChannels(channels *k8scommon.ResourceChannels, nsQuery *k8scommon.NamespaceQuery, dsQuery *dataselect.DataSelectQuery) (*PersistentVolumeClaimList, error) { - - persistentVolumeClaims := <-channels.PersistentVolumeClaimList.List - err := <-channels.PersistentVolumeClaimList.Error - if err != nil { - return nil, err - } - - return toPersistentVolumeClaimList(persistentVolumeClaims.Items, dsQuery), nil -} - -func toPersistentVolumeClaim(pvc v1.PersistentVolumeClaim) PersistentVolumeClaim { - - return PersistentVolumeClaim{ - ObjectMeta: k8s.NewObjectMeta(pvc.ObjectMeta), - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindPersistentVolumeClaim), - Status: string(pvc.Status.Phase), - Volume: pvc.Spec.VolumeName, - Capacity: pvc.Status.Capacity, - AccessModes: pvc.Spec.AccessModes, - StorageClass: pvc.Spec.StorageClassName, - } -} - -func toPersistentVolumeClaimList(persistentVolumeClaims []v1.PersistentVolumeClaim, dsQuery *dataselect.DataSelectQuery) *PersistentVolumeClaimList { - - result := &PersistentVolumeClaimList{ - Items: make([]PersistentVolumeClaim, 0), - ListMeta: k8s.ListMeta{TotalItems: len(persistentVolumeClaims)}, - } - - pvcCells, filteredTotal := dataselect.GenericDataSelectWithFilter(toCells(persistentVolumeClaims), dsQuery) - persistentVolumeClaims = fromCells(pvcCells) - result.ListMeta = k8s.ListMeta{TotalItems: filteredTotal} - - for _, item := range persistentVolumeClaims { - result.Items = append(result.Items, toPersistentVolumeClaim(item)) - } - - return result -} - -func DeletePersistentVolumeClaim(client *kubernetes.Clientset, namespace, name string) (err error) { - global.Log.Info(fmt.Sprintf("Start deleting persistent volumes claims, namespace: %v, name: %v", namespace, name)) - return client.CoreV1().PersistentVolumeClaims(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{}) -} diff --git a/apps/devops/services/k8s/pvc/pvc_common.go b/apps/devops/services/k8s/pvc/pvc_common.go deleted file mode 100644 index 8694853..0000000 --- a/apps/devops/services/k8s/pvc/pvc_common.go +++ /dev/null @@ -1,100 +0,0 @@ -package pvc - -import ( - "context" - "fmt" - "pandax/base/global" - - api "k8s.io/api/core/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - client "k8s.io/client-go/kubernetes" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" - "strings" -) - -// The code below allows to perform complex data section on []api.PersistentVolumeClaim - -type PersistentVolumeClaimCell api.PersistentVolumeClaim - -// GetPodPersistentVolumeClaims gets persistentvolumeclaims that are associated with this pod. -func GetPodPersistentVolumeClaims(client client.Interface, namespace string, podName string, dsQuery *dataselect.DataSelectQuery) (*PersistentVolumeClaimList, error) { - - pod, err := client.CoreV1().Pods(namespace).Get(context.TODO(), podName, metaV1.GetOptions{}) - if err != nil { - return nil, err - } - - claimNames := make([]string, 0) - if pod.Spec.Volumes != nil && len(pod.Spec.Volumes) > 0 { - for _, v := range pod.Spec.Volumes { - persistentVolumeClaim := v.PersistentVolumeClaim - if persistentVolumeClaim != nil { - claimNames = append(claimNames, persistentVolumeClaim.ClaimName) - } - } - } - - if len(claimNames) > 0 { - channels := &k8scommon.ResourceChannels{ - PersistentVolumeClaimList: k8scommon.GetPersistentVolumeClaimListChannel( - client, k8scommon.NewSameNamespaceQuery(namespace), 1), - } - - persistentVolumeClaimList := <-channels.PersistentVolumeClaimList.List - - err = <-channels.PersistentVolumeClaimList.Error - if err != nil { - return nil, err - } - - podPersistentVolumeClaims := make([]api.PersistentVolumeClaim, 0) - for _, pvc := range persistentVolumeClaimList.Items { - for _, claimName := range claimNames { - if strings.Compare(claimName, pvc.Name) == 0 { - podPersistentVolumeClaims = append(podPersistentVolumeClaims, pvc) - break - } - } - } - - global.Log.Info(fmt.Sprintf("Found %d persistentvolumeclaims related to %s pod", len(podPersistentVolumeClaims), podName)) - - return toPersistentVolumeClaimList(podPersistentVolumeClaims, dsQuery), nil - } - - global.Log.Warn(fmt.Sprintf("No persistentvolumeclaims found related to %s pod", podName)) - - // No ClaimNames found in Pod details, return empty response. - return &PersistentVolumeClaimList{}, nil -} - -func (self PersistentVolumeClaimCell) GetProperty(name dataselect.PropertyName) dataselect.ComparableValue { - switch name { - case dataselect.NameProperty: - return dataselect.StdComparableString(self.ObjectMeta.Name) - case dataselect.CreationTimestampProperty: - return dataselect.StdComparableTime(self.ObjectMeta.CreationTimestamp.Time) - case dataselect.NamespaceProperty: - return dataselect.StdComparableString(self.ObjectMeta.Namespace) - default: - // if name is not supported then just return a constant dummy value, sort will have no effect. - return nil - } -} - -func toCells(std []api.PersistentVolumeClaim) []dataselect.DataCell { - cells := make([]dataselect.DataCell, len(std)) - for i := range std { - cells[i] = PersistentVolumeClaimCell(std[i]) - } - return cells -} - -func fromCells(cells []dataselect.DataCell) []api.PersistentVolumeClaim { - std := make([]api.PersistentVolumeClaim, len(cells)) - for i := range std { - std[i] = api.PersistentVolumeClaim(cells[i].(PersistentVolumeClaimCell)) - } - return std -} diff --git a/apps/devops/services/k8s/pvc/pvc_detail.go b/apps/devops/services/k8s/pvc/pvc_detail.go deleted file mode 100644 index a3f7e80..0000000 --- a/apps/devops/services/k8s/pvc/pvc_detail.go +++ /dev/null @@ -1,35 +0,0 @@ -package pvc - -import ( - "context" - "fmt" - "pandax/base/global" - - v1 "k8s.io/api/core/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" -) - -// PersistentVolumeClaimDetail provides the presentation layer view of Kubernetes Persistent Volume Claim resource. -type PersistentVolumeClaimDetail struct { - // Extends list item structure. - PersistentVolumeClaim `json:",inline"` -} - -// GetPersistentVolumeClaimDetail returns detailed information about a persistent volume claim -func GetPersistentVolumeClaimDetail(client kubernetes.Interface, namespace string, name string) (*PersistentVolumeClaimDetail, error) { - global.Log.Info(fmt.Sprintf("Getting details of %s persistent volume claim", name)) - - pvc, err := client.CoreV1().PersistentVolumeClaims(namespace).Get(context.TODO(), name, metaV1.GetOptions{}) - if err != nil { - return nil, err - } - - return getPersistentVolumeClaimDetail(*pvc), nil -} - -func getPersistentVolumeClaimDetail(pvc v1.PersistentVolumeClaim) *PersistentVolumeClaimDetail { - return &PersistentVolumeClaimDetail{ - PersistentVolumeClaim: toPersistentVolumeClaim(pvc), - } -} diff --git a/apps/devops/services/k8s/secret/secret.go b/apps/devops/services/k8s/secret/secret.go deleted file mode 100644 index 2a4ceae..0000000 --- a/apps/devops/services/k8s/secret/secret.go +++ /dev/null @@ -1,145 +0,0 @@ -package secret - -import ( - "context" - "fmt" - "pandax/base/global" - - v1 "k8s.io/api/core/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" -) - -// SecretSpec is a common interface for the specification of different secrets. -type SecretSpec interface { - GetName() string - GetType() v1.SecretType - GetNamespace() string - GetData() map[string][]byte -} - -// ImagePullSecretSpec is a specification of an image pull secret implements SecretSpec -type ImagePullSecretSpec struct { - Name string `json:"name"` - Namespace string `json:"namespace"` - - // The value of the .dockercfg property. It must be Base64 encoded. - Data []byte `json:"data"` -} - -// GetName returns the name of the ImagePullSecret -func (spec *ImagePullSecretSpec) GetName() string { - return spec.Name -} - -// GetType returns the type of the ImagePullSecret, which is always api.SecretTypeDockercfg -func (spec *ImagePullSecretSpec) GetType() v1.SecretType { - return v1.SecretTypeDockercfg -} - -// GetNamespace returns the namespace of the ImagePullSecret -func (spec *ImagePullSecretSpec) GetNamespace() string { - return spec.Namespace -} - -// GetData returns the data the secret carries, it is a single key-value pair -func (spec *ImagePullSecretSpec) GetData() map[string][]byte { - return map[string][]byte{v1.DockerConfigKey: spec.Data} -} - -// Secret is a single secret returned to the frontend. -type Secret struct { - ObjectMeta k8s.ObjectMeta `json:"objectMeta"` - TypeMeta k8s.TypeMeta `json:"typeMeta"` - Type v1.SecretType `json:"type"` -} - -// SecretList is a response structure for a queried secrets list. -type SecretList struct { - k8s.ListMeta `json:"listMeta"` - - // Unordered list of Secrets. - Secrets []Secret `json:"secrets"` -} - -// GetSecretList returns all secrets in the given namespace. -func GetSecretList(client kubernetes.Interface, namespace *k8scommon.NamespaceQuery, dsQuery *dataselect.DataSelectQuery) (*SecretList, error) { - global.Log.Info(fmt.Sprintf("Getting list of secrets in %s namespace", namespace)) - secretList, err := client.CoreV1().Secrets(namespace.ToRequestParam()).List(context.TODO(), k8s.ListEverything) - if err != nil { - return nil, err - } - - return ToSecretList(secretList.Items, dsQuery), nil -} - -// CreateSecret creates a single secret using the cluster API client -func CreateSecret(client kubernetes.Interface, spec SecretSpec) (*Secret, error) { - namespace := spec.GetNamespace() - secret := &v1.Secret{ - ObjectMeta: metaV1.ObjectMeta{ - Name: spec.GetName(), - Namespace: namespace, - }, - Type: spec.GetType(), - Data: spec.GetData(), - } - _, err := client.CoreV1().Secrets(namespace).Create(context.TODO(), secret, metaV1.CreateOptions{}) - result := toSecret(secret) - return &result, err -} - -func toSecret(secret *v1.Secret) Secret { - return Secret{ - ObjectMeta: k8s.NewObjectMeta(secret.ObjectMeta), - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindSecret), - Type: secret.Type, - } -} - -func ToSecretList(secrets []v1.Secret, dsQuery *dataselect.DataSelectQuery) *SecretList { - newSecretList := &SecretList{ - ListMeta: k8s.ListMeta{TotalItems: len(secrets)}, - Secrets: make([]Secret, 0), - } - - secretCells, filteredTotal := dataselect.GenericDataSelectWithFilter(toCells(secrets), dsQuery) - secrets = fromCells(secretCells) - newSecretList.ListMeta = k8s.ListMeta{TotalItems: filteredTotal} - - for _, secret := range secrets { - newSecretList.Secrets = append(newSecretList.Secrets, toSecret(&secret)) - } - - return newSecretList -} - -func DeleteSecret(client *kubernetes.Clientset, namespace string, name string) error { - global.Log.Info(fmt.Sprintf("请求删除Secret: %v, namespace: %v", name, namespace)) - return client.CoreV1().Secrets(namespace).Delete( - context.TODO(), - name, - metaV1.DeleteOptions{}, - ) -} - -func DeleteCollectionSecret(client *kubernetes.Clientset, secretList []k8s.SecretsData) (err error) { - global.Log.Info("批量删除Secret开始") - for _, v := range secretList { - global.Log.Info(fmt.Sprintf("delete Secret:%v, ns: %v", v.Name, v.Namespace)) - err := client.CoreV1().Secrets(v.Namespace).Delete( - context.TODO(), - v.Name, - metaV1.DeleteOptions{}, - ) - if err != nil { - global.Log.Error(err.Error()) - return err - } - } - global.Log.Info("删除Secret已完成") - return nil -} diff --git a/apps/devops/services/k8s/secret/secret_common.go b/apps/devops/services/k8s/secret/secret_common.go deleted file mode 100644 index 2388060..0000000 --- a/apps/devops/services/k8s/secret/secret_common.go +++ /dev/null @@ -1,40 +0,0 @@ -package secret - -import ( - api "k8s.io/api/core/v1" - "pandax/apps/devops/services/k8s/dataselect" -) - -// The code below allows to perform complex data section on []api.Secret - -type SecretCell api.Secret - -func (self SecretCell) GetProperty(name dataselect.PropertyName) dataselect.ComparableValue { - switch name { - case dataselect.NameProperty: - return dataselect.StdComparableString(self.ObjectMeta.Name) - case dataselect.CreationTimestampProperty: - return dataselect.StdComparableTime(self.ObjectMeta.CreationTimestamp.Time) - case dataselect.NamespaceProperty: - return dataselect.StdComparableString(self.ObjectMeta.Namespace) - default: - // if name is not supported then just return a constant dummy value, sort will have no effect. - return nil - } -} - -func toCells(std []api.Secret) []dataselect.DataCell { - cells := make([]dataselect.DataCell, len(std)) - for i := range std { - cells[i] = SecretCell(std[i]) - } - return cells -} - -func fromCells(cells []dataselect.DataCell) []api.Secret { - std := make([]api.Secret, len(cells)) - for i := range std { - std[i] = api.Secret(cells[i].(SecretCell)) - } - return std -} diff --git a/apps/devops/services/k8s/secret/secret_detail.go b/apps/devops/services/k8s/secret/secret_detail.go deleted file mode 100644 index adabd65..0000000 --- a/apps/devops/services/k8s/secret/secret_detail.go +++ /dev/null @@ -1,43 +0,0 @@ -package secret - -import ( - "context" - "fmt" - "pandax/base/global" - - v1 "k8s.io/api/core/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" -) - -// SecretDetail API resource provides mechanisms to inject containers with configuration data while keeping -// containers agnostic of Kubernetes -type SecretDetail struct { - // Extends list item structure. - Secret `json:",inline"` - - // Data contains the secret data. Each key must be a valid DNS_SUBDOMAIN - // or leading dot followed by valid DNS_SUBDOMAIN. - // The serialized form of the secret data is a base64 encoded string, - // representing the arbitrary (possibly non-string) data value here. - Data map[string][]byte `json:"data"` -} - -// GetSecretDetail returns detailed information about a secret -func GetSecretDetail(client kubernetes.Interface, namespace, name string) (*SecretDetail, error) { - global.Log.Info(fmt.Sprintf("Getting details of %s secret in %s namespace", name, namespace)) - - rawSecret, err := client.CoreV1().Secrets(namespace).Get(context.TODO(), name, metaV1.GetOptions{}) - if err != nil { - return nil, err - } - - return getSecretDetail(rawSecret), nil -} - -func getSecretDetail(rawSecret *v1.Secret) *SecretDetail { - return &SecretDetail{ - Secret: toSecret(rawSecret), - Data: rawSecret.Data, - } -} diff --git a/apps/devops/services/k8s/service/events.go b/apps/devops/services/k8s/service/events.go deleted file mode 100644 index 180f66c..0000000 --- a/apps/devops/services/k8s/service/events.go +++ /dev/null @@ -1,29 +0,0 @@ -package service - -import ( - "fmt" - "pandax/base/global" - - client "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" - "pandax/apps/devops/services/k8s/event" -) - -// GetServiceEvents returns model events for a service with the given name in the given namespace. -func GetServiceEvents(client *client.Clientset, dsQuery *dataselect.DataSelectQuery, namespace, name string) (*k8scommon.EventList, error) { - eventList := k8scommon.EventList{ - Events: make([]k8scommon.Event, 0), - ListMeta: k8s.ListMeta{TotalItems: 0}, - } - - serviceEvents, err := event.GetEvents(client, namespace, name) - if err != nil { - return &eventList, err - } - - eventList = event.CreateEventList(event.FillEventsType(serviceEvents), dsQuery) - global.Log.Info(fmt.Sprintf("Found %d events related to %s service in %s namespace", len(eventList.Events), name, namespace)) - return &eventList, nil -} diff --git a/apps/devops/services/k8s/service/pods.go b/apps/devops/services/k8s/service/pods.go deleted file mode 100644 index a405e12..0000000 --- a/apps/devops/services/k8s/service/pods.go +++ /dev/null @@ -1,52 +0,0 @@ -package service - -import ( - "context" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/kubernetes" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" - "pandax/apps/devops/services/k8s/event" - "pandax/apps/devops/services/k8s/pods" -) - -// GetServicePods gets list of pods targeted by given label selector in given namespace. -func GetServicePods(client *kubernetes.Clientset, namespace, name string, dsQuery *dataselect.DataSelectQuery) (*pods.PodList, error) { - podList := pods.PodList{ - Pods: []pods.Pod{}, - } - - service, err := client.CoreV1().Services(namespace).Get(context.TODO(), name, metaV1.GetOptions{}) - if err != nil { - return &podList, err - } - - if service.Spec.Selector == nil { - return &podList, nil - } - - labelSelector := labels.SelectorFromSet(service.Spec.Selector) - channels := &k8scommon.ResourceChannels{ - PodList: k8scommon.GetPodListChannelWithOptions(client, k8scommon.NewSameNamespaceQuery(namespace), - metaV1.ListOptions{ - LabelSelector: labelSelector.String(), - FieldSelector: fields.Everything().String(), - }, 1), - } - - apiPodList := <-channels.PodList.List - if err := <-channels.PodList.Error; err != nil { - return &podList, err - } - - events, err := event.GetPodsEvents(client, namespace, apiPodList.Items) - - if err != nil { - return &podList, err - } - - podList = pods.ToPodList(apiPodList.Items, events, dsQuery) - return &podList, nil -} diff --git a/apps/devops/services/k8s/service/service.go b/apps/devops/services/k8s/service/service.go deleted file mode 100644 index 0bb01a5..0000000 --- a/apps/devops/services/k8s/service/service.go +++ /dev/null @@ -1,149 +0,0 @@ -package service - -import ( - "context" - "errors" - "fmt" - "pandax/base/global" - - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" - "strings" -) - -// Service is a representation of a service. -type Service struct { - ObjectMeta k8s.ObjectMeta `json:"objectMeta"` - TypeMeta k8s.TypeMeta `json:"typeMeta"` - - // InternalEndpoint of all Kubernetes services that have the same label selector as connected Replication - // Controller. Endpoint is DNS name merged with ports. - InternalEndpoint k8scommon.Endpoint `json:"internalEndpoint"` - - // ExternalEndpoints of all Kubernetes services that have the same label selector as connected Replication - // Controller. Endpoint is external IP address name merged with ports. - ExternalEndpoints []k8scommon.Endpoint `json:"externalEndpoints"` - - // Label selector of the service. - Selector map[string]string `json:"selector"` - - // Type determines how the service will be exposed. Valid options: ClusterIP, NodePort, LoadBalancer, ExternalName - Type v1.ServiceType `json:"type"` - - // ClusterIP is usually assigned by the master. Valid values are None, empty string (""), or - // a valid IP address. None can be specified for headless services when proxying is not required - ClusterIP string `json:"clusterIP"` -} - -// ServiceList contains a list of services in the cluster. -type ServiceList struct { - ListMeta k8s.ListMeta `json:"listMeta"` - - // Unordered list of services. - Services []Service `json:"services"` -} - -// GetServiceList returns a list of all services in the cluster. -func GetServiceList(client *kubernetes.Clientset, nsQuery *k8scommon.NamespaceQuery, dsQuery *dataselect.DataSelectQuery) (*ServiceList, error) { - global.Log.Info("Getting list of all services in the cluster") - - channels := &k8scommon.ResourceChannels{ - ServiceList: k8scommon.GetServiceListChannel(client, nsQuery, 1), - } - - return GetServiceListFromChannels(channels, dsQuery) -} - -// GetServiceListFromChannels returns a list of all services in the cluster. -func GetServiceListFromChannels(channels *k8scommon.ResourceChannels, dsQuery *dataselect.DataSelectQuery) (*ServiceList, error) { - services := <-channels.ServiceList.List - err := <-channels.ServiceList.Error - if err != nil { - return nil, err - } - - return CreateServiceList(services.Items, dsQuery), nil -} - -func ToService(service *v1.Service) Service { - return Service{ - ObjectMeta: k8s.NewObjectMeta(service.ObjectMeta), - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindService), - InternalEndpoint: k8scommon.GetInternalEndpoint(service.Name, service.Namespace, service.Spec.Ports), - ExternalEndpoints: k8scommon.GetExternalEndpoints(service), - Selector: service.Spec.Selector, - ClusterIP: service.Spec.ClusterIP, - Type: service.Spec.Type, - } -} - -// CreateServiceList returns paginated service list based on given service array and pagination query. -func CreateServiceList(services []v1.Service, dsQuery *dataselect.DataSelectQuery) *ServiceList { - serviceList := &ServiceList{ - Services: make([]Service, 0), - ListMeta: k8s.ListMeta{TotalItems: len(services)}, - } - - serviceCells, filteredTotal := dataselect.GenericDataSelectWithFilter(toCells(services), dsQuery) - services = fromCells(serviceCells) - serviceList.ListMeta = k8s.ListMeta{TotalItems: filteredTotal} - - for _, service := range services { - serviceList.Services = append(serviceList.Services, ToService(&service)) - } - - return serviceList -} - -func DeleteService(client *kubernetes.Clientset, ns string, serviceName string) error { - global.Log.Info(fmt.Sprintf("请求删除Service: %v, namespace: %v", serviceName, ns)) - return client.CoreV1().Services(ns).Delete( - context.TODO(), - serviceName, - metav1.DeleteOptions{}, - ) -} - -func DeleteCollectionService(client *kubernetes.Clientset, serviceList []k8s.ServiceData) (err error) { - global.Log.Info("批量删除service开始") - for _, v := range serviceList { - global.Log.Info(fmt.Sprintf("delete service:%v, ns: %v", v.Name, v.Namespace)) - err := client.CoreV1().Services(v.Namespace).Delete( - context.TODO(), - v.Name, - metav1.DeleteOptions{}, - ) - if err != nil { - global.Log.Error(err.Error()) - return err - } - } - global.Log.Info("删除service已完成") - return nil -} - -func GetToService(client *kubernetes.Clientset, namespace string, name string) (*ServiceList, error) { - serviceList := &ServiceList{ - Services: make([]Service, 0), - } - svcList, err := client.CoreV1().Services(namespace).List(context.TODO(), metav1.ListOptions{}) - global.Log.Info("开始获取svc") - if err != nil { - return nil, err - } - for _, svc := range svcList.Items { - if strings.Contains(svc.Name, name) { - serviceList.Services = append(serviceList.Services, ToService(&svc)) - serviceList.ListMeta = k8s.ListMeta{ - TotalItems: len(serviceList.Services), - } - return serviceList, nil - } - } - global.Log.Warn(fmt.Sprintf("没有找到所关联的SVC:namespace: %s, name: %s", namespace, name)) - return nil, errors.New("没有找到所关联的SVC") -} diff --git a/apps/devops/services/k8s/service/service_common.go b/apps/devops/services/k8s/service/service_common.go deleted file mode 100644 index a0705e2..0000000 --- a/apps/devops/services/k8s/service/service_common.go +++ /dev/null @@ -1,42 +0,0 @@ -package service - -import ( - v1 "k8s.io/api/core/v1" - "pandax/apps/devops/services/k8s/dataselect" -) - -// The code below allows to perform complex data section on []api.Service - -type ServiceCell v1.Service - -func (self ServiceCell) GetProperty(name dataselect.PropertyName) dataselect.ComparableValue { - switch name { - case dataselect.NameProperty: - return dataselect.StdComparableString(self.ObjectMeta.Name) - case dataselect.CreationTimestampProperty: - return dataselect.StdComparableTime(self.ObjectMeta.CreationTimestamp.Time) - case dataselect.NamespaceProperty: - return dataselect.StdComparableString(self.ObjectMeta.Namespace) - case dataselect.TypeProperty: - return dataselect.StdComparableString(self.Spec.Type) - default: - // if name is not supported then just return a constant dummy value, sort will have no effect. - return nil - } -} - -func toCells(std []v1.Service) []dataselect.DataCell { - cells := make([]dataselect.DataCell, len(std)) - for i := range std { - cells[i] = ServiceCell(std[i]) - } - return cells -} - -func fromCells(cells []dataselect.DataCell) []v1.Service { - std := make([]v1.Service, len(cells)) - for i := range std { - std[i] = v1.Service(cells[i].(ServiceCell)) - } - return std -} diff --git a/apps/devops/services/k8s/service/service_detail.go b/apps/devops/services/k8s/service/service_detail.go deleted file mode 100644 index 8694d23..0000000 --- a/apps/devops/services/k8s/service/service_detail.go +++ /dev/null @@ -1,67 +0,0 @@ -package service - -import ( - "context" - "fmt" - "pandax/base/global" - - v1 "k8s.io/api/core/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" - "pandax/apps/devops/services/k8s/endpoint" - "pandax/apps/devops/services/k8s/pods" -) - -// ServiceDetail is a representation of a service. -type ServiceDetail struct { - // Extends list item structure. - Service `json:",inline"` - - // List of Endpoint obj. that are endpoints of this Service. - EndpointList endpoint.EndpointList `json:"endpointList"` - - // Show the value of the SessionAffinity of the Service. - SessionAffinity v1.ServiceAffinity `json:"sessionAffinity"` - - EventList *k8scommon.EventList `json:"eventList"` - - PodList *pods.PodList `json:"podList"` -} - -// GetServiceDetail gets service details. -func GetServiceDetail(client *kubernetes.Clientset, namespace, name string, dsQuery *dataselect.DataSelectQuery) (*ServiceDetail, error) { - global.Log.Info(fmt.Sprintf("Getting details of %s service in %s namespace", name, namespace)) - serviceData, err := client.CoreV1().Services(namespace).Get(context.TODO(), name, metaV1.GetOptions{}) - if err != nil { - return nil, err - } - - endpointList, err := endpoint.GetServiceEndpoints(client, namespace, name) - if err != nil { - return nil, err - } - podList, err := GetServicePods(client, namespace, name, dsQuery) - if err != nil { - return nil, err - } - - eventList, err := GetServiceEvents(client, dataselect.DefaultDataSelect, namespace, name) - if err != nil { - return nil, err - } - - service := toServiceDetail(serviceData, *endpointList, podList, eventList) - return &service, nil -} - -func toServiceDetail(service *v1.Service, endpointList endpoint.EndpointList, podList *pods.PodList, eventList *k8scommon.EventList) ServiceDetail { - return ServiceDetail{ - Service: ToService(service), - EndpointList: endpointList, - PodList: podList, - EventList: eventList, - SessionAffinity: service.Spec.SessionAffinity, - } -} diff --git a/apps/devops/services/k8s/statefulset/statefulset.go b/apps/devops/services/k8s/statefulset/statefulset.go deleted file mode 100644 index 606999d..0000000 --- a/apps/devops/services/k8s/statefulset/statefulset.go +++ /dev/null @@ -1,236 +0,0 @@ -package statefulset - -import ( - "context" - "fmt" - "pandax/base/global" - - "go.uber.org/zap" - apps "k8s.io/api/apps/v1" - autoscalingv1 "k8s.io/api/autoscaling/v1" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" - "pandax/apps/devops/services/k8s/event" - "time" -) - -// StatefulSetList contains a list of Stateful Sets in the cluster. -type StatefulSetList struct { - ListMeta k8s.ListMeta `json:"listMeta"` - Status k8scommon.ResourceStatus `json:"status"` - StatefulSets []StatefulSet `json:"statefulSets"` -} - -// StatusInfo is the status information of the statefulSet -type StatusInfo struct { - // replicas is the number of Pods created by the StatefulSet controller. - Replicas int32 `json:"replicas"` - - // Number of non-terminated pods that have the desired template spec - Updated int32 `json:"updated"` - - // readyReplicas is the number of Pods created by the StatefulSet controller that have a Ready Condition. - ReadyReplicas int32 `json:"readyReplicas,omitempty"` - - // currentReplicas is the number of Pods created by the StatefulSet controller from the StatefulSet version - // indicated by currentRevision. - CurrentReplicas int32 `json:"currentReplicas,omitempty"` - - // updatedReplicas is the number of Pods created by the StatefulSet controller from the StatefulSet version - // indicated by updateRevision. - UpdatedReplicas int32 `json:"updatedReplicas,omitempty"` - // Total number of available pods (ready for at least minReadySeconds) targeted by this statefulset. - // This is an alpha field and requires enabling StatefulSetMinReadySeconds feature gate. - // Remove omitempty when graduating to beta - // +optional - AvailableReplicas int32 `json:"availableReplicas,omitempty"` -} - -// StatefulSet is a presentation layer view of Kubernetes Stateful Set resource. -type StatefulSet struct { - ObjectMeta k8s.ObjectMeta `json:"objectMeta"` - TypeMeta k8s.TypeMeta `json:"typeMeta"` - Pods k8scommon.PodInfo `json:"podInfo"` - - // Status information on the statefulSet - StatusInfo `json:"statusInfo"` - - // Label selector - Selector *metav1.LabelSelector `json:"selector"` - // The statefulset strategy to use to replace existing pods with new ones. - // Valid options: Recreate, RollingUpdate - Strategy apps.StatefulSetUpdateStrategy `json:"strategy"` - - ContainerImages []string `json:"containerImages"` - - InitContainerImages []string `json:"initContainerImages"` -} - -// GetStatefulSetList returns a list of all Stateful Sets in the cluster. -func GetStatefulSetList(client *kubernetes.Clientset, nsQuery *k8scommon.NamespaceQuery, dsQuery *dataselect.DataSelectQuery) (*StatefulSetList, error) { - global.Log.Info("Getting list of all pet sets in the cluster") - - channels := &k8scommon.ResourceChannels{ - StatefulSetList: k8scommon.GetStatefulSetListChannel(client, nsQuery, 1), - PodList: k8scommon.GetPodListChannel(client, nsQuery, 1), - EventList: k8scommon.GetEventListChannel(client, nsQuery, 1), - } - - return GetStatefulSetListFromChannels(channels, dsQuery) -} - -// GetStatefulSetListFromChannels returns a list of all Stateful Sets in the cluster reading -// required resource list once from the channels. -func GetStatefulSetListFromChannels(channels *k8scommon.ResourceChannels, dsQuery *dataselect.DataSelectQuery) (*StatefulSetList, error) { - - statefulSets := <-channels.StatefulSetList.List - err := <-channels.StatefulSetList.Error - if err != nil { - return nil, err - } - - pods := <-channels.PodList.List - err = <-channels.PodList.Error - if err != nil { - return nil, err - } - - events := <-channels.EventList.List - err = <-channels.EventList.Error - if err != nil { - return nil, err - } - - ssList := toStatefulSetList(statefulSets.Items, pods.Items, events.Items, dsQuery) - ssList.Status = getStatus(statefulSets, pods.Items, events.Items) - return ssList, nil -} - -func toStatefulSetList(statefulSets []apps.StatefulSet, pods []v1.Pod, events []v1.Event, dsQuery *dataselect.DataSelectQuery) *StatefulSetList { - - statefulSetList := &StatefulSetList{ - StatefulSets: make([]StatefulSet, 0), - ListMeta: k8s.ListMeta{TotalItems: len(statefulSets)}, - } - - ssCells, filteredTotal := dataselect.GenericDataSelectWithFilter(toCells(statefulSets), dsQuery) - statefulSets = fromCells(ssCells) - statefulSetList.ListMeta = k8s.ListMeta{TotalItems: filteredTotal} - - for _, statefulSet := range statefulSets { - matchingPods := k8scommon.FilterPodsByControllerRef(&statefulSet, pods) - podInfo := k8scommon.GetPodInfo(statefulSet.Status.Replicas, statefulSet.Spec.Replicas, matchingPods) - podInfo.Warnings = event.GetPodsEventWarnings(events, matchingPods) - statefulSetList.StatefulSets = append(statefulSetList.StatefulSets, toStatefulSet(&statefulSet, &podInfo)) - } - - return statefulSetList -} - -func toStatefulSet(statefulSet *apps.StatefulSet, podInfo *k8scommon.PodInfo) StatefulSet { - - return StatefulSet{ - ObjectMeta: k8s.NewObjectMeta(statefulSet.ObjectMeta), - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindStatefulSet), - StatusInfo: GetStatusInfo(&statefulSet.Status), - Selector: statefulSet.Spec.Selector, - Strategy: statefulSet.Spec.UpdateStrategy, - ContainerImages: k8scommon.GetContainerImages(&statefulSet.Spec.Template.Spec), - InitContainerImages: k8scommon.GetInitContainerImages(&statefulSet.Spec.Template.Spec), - Pods: *podInfo, - } -} - -func DeleteCollectionStatefulSet(client *kubernetes.Clientset, statefulSetList []k8s.StatefulSetData) (err error) { - global.Log.Info("批量删除statefulset开始") - for _, v := range statefulSetList { - global.Log.Info(fmt.Sprintf("delete statefulset:%v, ns: %v", v.Name, v.Namespace)) - err := client.AppsV1().StatefulSets(v.Namespace).Delete( - context.TODO(), - v.Name, - metav1.DeleteOptions{}, - ) - if err != nil { - global.Log.Error(err.Error()) - return err - } - } - global.Log.Info("删除statefulset已完成") - return nil -} - -func DeleteStatefulSet(client *kubernetes.Clientset, ns string, name string) (err error) { - global.Log.Info(fmt.Sprintf("请求删除单个statefulset:%v, namespace: %v", name, ns)) - return client.AppsV1().StatefulSets(ns).Delete( - context.TODO(), - name, - metav1.DeleteOptions{}, - ) -} - -func RestartStatefulSet(client *kubernetes.Clientset, name string, namespace string) (err error) { - global.Log.Info(fmt.Sprintf("下发应用重启指令, 名称空间:%v, 有状态应用:%v", namespace, name)) - data := fmt.Sprintf(`{"spec":{"template":{"metadata":{"annotations":{"kubectl.kubernetes.io/restartedAt":"%s"}}}}}`, time.Now().String()) - _, err = client.AppsV1().StatefulSets(namespace).Patch( - context.Background(), - name, - types.StrategicMergePatchType, - []byte(data), - metav1.PatchOptions{ - FieldManager: "kubectl-rollout", - }) - - if err != nil { - global.Log.Error("应用重启失败", zap.Any("err: ", err)) - return err - } - return nil -} - -func ScaleStatefulSet(client *kubernetes.Clientset, ns string, name string, scaleNumber int32) (err error) { - - global.Log.Info(fmt.Sprintf("start scale of %v statefulset in %v namespace", name, ns)) - - scaleData, err := client.AppsV1().StatefulSets(ns).GetScale( - context.TODO(), - name, - metav1.GetOptions{}, - ) - - global.Log.Info(fmt.Sprintf("The statefulset has changed from %v to %v", scaleData.Spec.Replicas, scaleNumber)) - - scale := autoscalingv1.Scale{ - TypeMeta: scaleData.TypeMeta, - ObjectMeta: scaleData.ObjectMeta, - Spec: autoscalingv1.ScaleSpec{Replicas: scaleNumber}, - Status: scaleData.Status, - } - _, err = client.AppsV1().StatefulSets(ns).UpdateScale( - context.TODO(), - name, - &scale, - metav1.UpdateOptions{}, - ) - - if err != nil { - global.Log.Error("扩缩容出现异常", zap.Any("err: ", err)) - return err - } - return nil -} - -// GetStatusInfo is used to get the status information from the *apps.StatefulSetStatus -func GetStatusInfo(statefulSetStatus *apps.StatefulSetStatus) StatusInfo { - return StatusInfo{ - Replicas: statefulSetStatus.Replicas, - Updated: statefulSetStatus.UpdatedReplicas, - //AvailableReplicas: statefulSetStatus.AvailableReplicas, - ReadyReplicas: statefulSetStatus.ReadyReplicas, - CurrentReplicas: statefulSetStatus.CurrentReplicas, - } -} diff --git a/apps/devops/services/k8s/statefulset/statefulset_common.go b/apps/devops/services/k8s/statefulset/statefulset_common.go deleted file mode 100644 index 5c5ae8d..0000000 --- a/apps/devops/services/k8s/statefulset/statefulset_common.go +++ /dev/null @@ -1,66 +0,0 @@ -package statefulset - -import ( - apps "k8s.io/api/apps/v1" - v1 "k8s.io/api/core/v1" - "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" - "pandax/apps/devops/services/k8s/event" -) - -// The code below allows to perform complex data section on []apps.StatefulSet - -type StatefulSetCell apps.StatefulSet - -func (self StatefulSetCell) GetProperty(name dataselect.PropertyName) dataselect.ComparableValue { - switch name { - case dataselect.NameProperty: - return dataselect.StdComparableString(self.ObjectMeta.Name) - case dataselect.CreationTimestampProperty: - return dataselect.StdComparableTime(self.ObjectMeta.CreationTimestamp.Time) - case dataselect.NamespaceProperty: - return dataselect.StdComparableString(self.ObjectMeta.Namespace) - default: - // if name is not supported then just return a constant dummy value, sort will have no effect. - return nil - } -} - -func toCells(std []apps.StatefulSet) []dataselect.DataCell { - cells := make([]dataselect.DataCell, len(std)) - for i := range std { - cells[i] = StatefulSetCell(std[i]) - } - return cells -} - -func fromCells(cells []dataselect.DataCell) []apps.StatefulSet { - std := make([]apps.StatefulSet, len(cells)) - for i := range std { - std[i] = apps.StatefulSet(cells[i].(StatefulSetCell)) - } - return std -} - -func getStatus(list *apps.StatefulSetList, pods []v1.Pod, events []v1.Event) common.ResourceStatus { - info := common.ResourceStatus{} - if list == nil { - return info - } - - for _, ss := range list.Items { - matchingPods := common.FilterPodsByControllerRef(&ss, pods) - podInfo := common.GetPodInfo(ss.Status.Replicas, ss.Spec.Replicas, matchingPods) - warnings := event.GetPodsEventWarnings(events, matchingPods) - - if len(warnings) > 0 { - info.Failed++ - } else if podInfo.Pending > 0 { - info.Pending++ - } else { - info.Running++ - } - } - - return info -} diff --git a/apps/devops/services/k8s/statefulset/statefulset_detail.go b/apps/devops/services/k8s/statefulset/statefulset_detail.go deleted file mode 100644 index e03cbde..0000000 --- a/apps/devops/services/k8s/statefulset/statefulset_detail.go +++ /dev/null @@ -1,61 +0,0 @@ -package statefulset - -import ( - "context" - "fmt" - "pandax/base/global" - - apps "k8s.io/api/apps/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" - "pandax/apps/devops/services/k8s/event" - "pandax/apps/devops/services/k8s/service" -) - -// StatefulSetDetail is a presentation layer view of Kubernetes Stateful Set resource. This means it is Stateful -type StatefulSetDetail struct { - // Extends list item structure. - StatefulSet `json:",inline"` - - Events *k8scommon.EventList `json:"events"` - - PodList *PodList `json:"podList"` - - SvcList *service.ServiceList `json:"svcList"` -} - -// GetStatefulSetDetail gets Stateful Set details. -func GetStatefulSetDetail(client *kubernetes.Clientset, dsQuery *dataselect.DataSelectQuery, namespace, name string) (*StatefulSetDetail, error) { - global.Log.Info(fmt.Sprintf("Getting details of %s statefulset in %s namespace", name, namespace)) - - ss, err := client.AppsV1().StatefulSets(namespace).Get(context.TODO(), name, metaV1.GetOptions{}) - if err != nil { - return nil, err - } - - podInfo, err := getStatefulSetPodInfo(client, ss) - if err != nil { - return nil, err - } - events, err := event.GetResourceEvents(client, dsQuery, namespace, name) - if err != nil { - return nil, err - } - - serviceList, _ := service.GetToService(client, namespace, name) - ssDetail := getStatefulSetDetail(ss, podInfo, events, serviceList, client) - return &ssDetail, nil -} - -func getStatefulSetDetail(statefulSet *apps.StatefulSet, podInfo *k8scommon.PodInfo, - events *k8scommon.EventList, svc *service.ServiceList, client *kubernetes.Clientset) StatefulSetDetail { - - return StatefulSetDetail{ - StatefulSet: toStatefulSet(statefulSet, podInfo), - Events: events, - PodList: getStatefulSetToPod(client, statefulSet), - SvcList: svc, - } -} diff --git a/apps/devops/services/k8s/statefulset/statefulset_pods.go b/apps/devops/services/k8s/statefulset/statefulset_pods.go deleted file mode 100644 index 10b717d..0000000 --- a/apps/devops/services/k8s/statefulset/statefulset_pods.go +++ /dev/null @@ -1,80 +0,0 @@ -package statefulset - -import ( - "context" - "pandax/base/global" - - "go.uber.org/zap" - apps "k8s.io/api/apps/v1" - v1 "k8s.io/api/core/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/event" - "pandax/apps/devops/services/k8s/pods" -) - -type PodList struct { - ListMeta k8s.ListMeta `json:"listMeta"` - - // Basic information about resources status on the list. - Status k8scommon.ResourceStatus `json:"status"` - - // Unordered list of Pods. - Pods []pods.Pod `json:"pods"` -} - -// Returns simple info about pods(running, desired, failing, etc.) related to given pet set. -func getStatefulSetPodInfo(client kubernetes.Interface, statefulSet *apps.StatefulSet) (*k8scommon.PodInfo, error) { - podList, err := getRawStatefulSetPods(client, statefulSet.Name, statefulSet.Namespace) - if err != nil { - return nil, err - } - - podInfo := k8scommon.GetPodInfo(statefulSet.Status.Replicas, statefulSet.Spec.Replicas, podList) - return &podInfo, nil -} - -// getRawStatefulSetPods return array of api pods targeting pet set with given name. -func getRawStatefulSetPods(client kubernetes.Interface, name, namespace string) ([]v1.Pod, error) { - statefulSet, err := client.AppsV1().StatefulSets(namespace).Get(context.TODO(), name, metaV1.GetOptions{}) - if err != nil { - return nil, err - } - - channels := &k8scommon.ResourceChannels{ - PodList: k8scommon.GetPodListChannel(client, k8scommon.NewSameNamespaceQuery(namespace), 1), - } - - podList := <-channels.PodList.List - if err := <-channels.PodList.Error; err != nil { - return nil, err - } - - return k8scommon.FilterPodsByControllerRef(statefulSet, podList.Items), nil -} - -func getStatefulSetToPod(client *kubernetes.Clientset, stateful *apps.StatefulSet) (po *PodList) { - - selector, err := metaV1.LabelSelectorAsSelector(stateful.Spec.Selector) - if err != nil { - return nil - } - options := metaV1.ListOptions{LabelSelector: selector.String()} - - podData, err := client.CoreV1().Pods(stateful.Namespace).List(context.TODO(), options) - if err != nil { - global.Log.Error("Get a pod exception from the statefulSet", zap.Any("err", err)) - } - podList := PodList{ - Pods: make([]pods.Pod, 0), - } - podList.ListMeta = k8s.ListMeta{TotalItems: len(podData.Items)} - for _, pod := range podData.Items { - warnings := event.GetPodsEventWarnings(nil, []v1.Pod{pod}) - podDetail := pods.ToPod(&pod, warnings) - podList.Pods = append(podList.Pods, podDetail) - } - return &podList -} diff --git a/apps/devops/services/k8s/storageclass/sc.go b/apps/devops/services/k8s/storageclass/sc.go deleted file mode 100644 index 748d8f3..0000000 --- a/apps/devops/services/k8s/storageclass/sc.go +++ /dev/null @@ -1,89 +0,0 @@ -package storageclass - -import ( - "context" - "fmt" - "pandax/base/global" - - v1 "k8s.io/api/core/v1" - storage "k8s.io/api/storage/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/entity/k8s" - k8scommon "pandax/apps/devops/services/k8s/common" - "pandax/apps/devops/services/k8s/dataselect" -) - -// StorageClassList holds a list of Storage Class objects in the cluster. -type StorageClassList struct { - ListMeta k8s.ListMeta `json:"listMeta"` - Items []StorageClass `json:"items"` -} - -// StorageClass is a representation of a Kubernetes Storage Class object. -type StorageClass struct { - ObjectMeta k8s.ObjectMeta `json:"objectMeta"` - TypeMeta k8s.TypeMeta `json:"typeMeta"` - Provisioner string `json:"provisioner"` - Parameters map[string]string `json:"parameters"` - ReclaimPolicy *v1.PersistentVolumeReclaimPolicy `json:"reclaimPolicy,omitempty"` -} - -// GetStorageClassList returns a list of all storage class objects in the cluster. -func GetStorageClassList(client kubernetes.Interface, dsQuery *dataselect.DataSelectQuery) (*StorageClassList, error) { - global.Log.Info("Getting list of storage classes in the cluster") - - channels := &k8scommon.ResourceChannels{ - StorageClassList: k8scommon.GetStorageClassListChannel(client, 1), - } - - return GetStorageClassListFromChannels(channels, dsQuery) -} - -// GetStorageClassListFromChannels returns a list of all storage class objects in the cluster. -func GetStorageClassListFromChannels(channels *k8scommon.ResourceChannels, - dsQuery *dataselect.DataSelectQuery) (*StorageClassList, error) { - storageClasses := <-channels.StorageClassList.List - err := <-channels.StorageClassList.Error - if err != nil { - return nil, err - } - - return toStorageClassList(storageClasses.Items, dsQuery), nil -} - -func toStorageClassList(storageClasses []storage.StorageClass, dsQuery *dataselect.DataSelectQuery) *StorageClassList { - - storageClassList := &StorageClassList{ - Items: make([]StorageClass, 0), - ListMeta: k8s.ListMeta{TotalItems: len(storageClasses)}, - } - - storageClassCells, filteredTotal := dataselect.GenericDataSelectWithFilter(toCells(storageClasses), dsQuery) - storageClasses = fromCells(storageClassCells) - storageClassList.ListMeta = k8s.ListMeta{TotalItems: filteredTotal} - - for _, storageClass := range storageClasses { - storageClassList.Items = append(storageClassList.Items, toStorageClass(&storageClass)) - } - - return storageClassList -} - -func toStorageClass(storageClass *storage.StorageClass) StorageClass { - - return StorageClass{ - ObjectMeta: k8s.NewObjectMeta(storageClass.ObjectMeta), - TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindStorageClass), - Provisioner: storageClass.Provisioner, - Parameters: storageClass.Parameters, - ReclaimPolicy: storageClass.ReclaimPolicy, - } -} - -func DeleteStorageClass(client kubernetes.Interface, name string) (err error) { - global.Log.Info(fmt.Sprintf("delete of %s storage class", name)) - - return client.StorageV1().StorageClasses().Delete(context.TODO(), name, metaV1.DeleteOptions{}) - -} diff --git a/apps/devops/services/k8s/storageclass/sc_common.go b/apps/devops/services/k8s/storageclass/sc_common.go deleted file mode 100644 index 03e7661..0000000 --- a/apps/devops/services/k8s/storageclass/sc_common.go +++ /dev/null @@ -1,40 +0,0 @@ -package storageclass - -import ( - storage "k8s.io/api/storage/v1" - "pandax/apps/devops/services/k8s/dataselect" -) - -// The code below allows to perform complex data section on []storage.StorageClass - -type StorageClassCell storage.StorageClass - -func (self StorageClassCell) GetProperty(name dataselect.PropertyName) dataselect.ComparableValue { - switch name { - case dataselect.NameProperty: - return dataselect.StdComparableString(self.ObjectMeta.Name) - case dataselect.CreationTimestampProperty: - return dataselect.StdComparableTime(self.ObjectMeta.CreationTimestamp.Time) - case dataselect.NamespaceProperty: - return dataselect.StdComparableString(self.ObjectMeta.Namespace) - default: - // if name is not supported then just return a constant dummy value, sort will have no effect. - return nil - } -} - -func toCells(std []storage.StorageClass) []dataselect.DataCell { - cells := make([]dataselect.DataCell, len(std)) - for i := range std { - cells[i] = StorageClassCell(std[i]) - } - return cells -} - -func fromCells(cells []dataselect.DataCell) []storage.StorageClass { - std := make([]storage.StorageClass, len(cells)) - for i := range std { - std[i] = storage.StorageClass(cells[i].(StorageClassCell)) - } - return std -} diff --git a/apps/devops/services/k8s/storageclass/sc_detail.go b/apps/devops/services/k8s/storageclass/sc_detail.go deleted file mode 100644 index 9648cba..0000000 --- a/apps/devops/services/k8s/storageclass/sc_detail.go +++ /dev/null @@ -1,41 +0,0 @@ -package storageclass - -import ( - "context" - "fmt" - "pandax/base/global" - - storage "k8s.io/api/storage/v1" - metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "pandax/apps/devops/services/k8s/dataselect" - "pandax/apps/devops/services/k8s/pv" -) - -// StorageClassDetail provides the presentation layer view of Storage Class resource. -type StorageClassDetail struct { - // Extends list item structure. - StorageClass `json:",inline"` - PersistentVolumeList pv.PersistentVolumeList `json:"persistentVolumeList"` -} - -// GetStorageClassDetail returns Storage Class resource. -func GetStorageClassDetail(client kubernetes.Interface, name string) (*StorageClassDetail, error) { - global.Log.Info(fmt.Sprintf("Getting details of %s storage class", name)) - - sc, err := client.StorageV1().StorageClasses().Get(context.TODO(), name, metaV1.GetOptions{}) - if err != nil { - return nil, err - } - persistentVolumeList, err := pv.GetStorageClassPersistentVolumes(client, sc.Name, dataselect.DefaultDataSelect) - - storageClass := toStorageClassDetail(sc, persistentVolumeList) - return &storageClass, err -} - -func toStorageClassDetail(storageClass *storage.StorageClass, persistentVolumeList *pv.PersistentVolumeList) StorageClassDetail { - return StorageClassDetail{ - StorageClass: toStorageClass(storageClass), - PersistentVolumeList: *persistentVolumeList, - } -} diff --git a/apps/devops/services/k8s/terminal/terminal.go b/apps/devops/services/k8s/terminal/terminal.go deleted file mode 100644 index c7aabe5..0000000 --- a/apps/devops/services/k8s/terminal/terminal.go +++ /dev/null @@ -1,297 +0,0 @@ -package terminal - -import ( - "crypto/rand" - "encoding/hex" - "encoding/json" - "fmt" - "github.com/gin-gonic/gin" - "io" - "log" - "net/http" - "sync" - - "gopkg.in/igm/sockjs-go.v2/sockjs" - v1 "k8s.io/api/core/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/remotecommand" -) - -const END_OF_TRANSMISSION = "\u0004" - -// PtyHandler is what remotecommand expects from a pty -type PtyHandler interface { - io.Reader - io.Writer - remotecommand.TerminalSizeQueue -} - -// TerminalSession implements PtyHandler (using a SockJS connection) -type TerminalSession struct { - id string - bound chan error - sockJSSession sockjs.Session - sizeChan chan remotecommand.TerminalSize - doneChan chan struct{} -} - -// TerminalMessage is the messaging protocol between ShellController and TerminalSession. -// -// OP DIRECTION FIELD(S) USED DESCRIPTION -// --------------------------------------------------------------------- -// bind fe->be SessionID Id sent back from TerminalResponse -// stdin fe->be Data Keystrokes/paste buffer -// resize fe->be Rows, Cols New terminal size -// stdout be->fe Data Output from the process -// toast be->fe Data OOB message to be shown to the user -type TerminalMessage struct { - Op, Data, SessionID string - Rows, Cols uint16 -} - -// TerminalSize handles pty->process resize events -// Called in a loop from remotecommand as long as the process is running -func (t TerminalSession) Next() *remotecommand.TerminalSize { - select { - case size := <-t.sizeChan: - return &size - case <-t.doneChan: - return nil - } -} - -// Read handles pty->process messages (stdin, resize) -// Called in a loop from remotecommand as long as the process is running -func (t TerminalSession) Read(p []byte) (int, error) { - m, err := t.sockJSSession.Recv() - if err != nil { - // Send terminated signal to process to avoid resource leak - return copy(p, END_OF_TRANSMISSION), err - } - - var msg TerminalMessage - if err := json.Unmarshal([]byte(m), &msg); err != nil { - return copy(p, END_OF_TRANSMISSION), err - } - - switch msg.Op { - case "stdin": - return copy(p, msg.Data), nil - case "resize": - t.sizeChan <- remotecommand.TerminalSize{Width: msg.Cols, Height: msg.Rows} - return 0, nil - default: - return copy(p, END_OF_TRANSMISSION), fmt.Errorf("unknown message type '%s'", msg.Op) - } -} - -// Write handles process->pty stdout -// Called from remotecommand whenever there is any output -func (t TerminalSession) Write(p []byte) (int, error) { - msg, err := json.Marshal(TerminalMessage{ - Op: "stdout", - Data: string(p), - }) - if err != nil { - return 0, err - } - - if err = t.sockJSSession.Send(string(msg)); err != nil { - return 0, err - } - return len(p), nil -} - -// Toast can be used to send the user any OOB messages -// hterm puts these in the center of the terminal -func (t TerminalSession) Toast(p string) error { - msg, err := json.Marshal(TerminalMessage{ - Op: "toast", - Data: p, - }) - if err != nil { - return err - } - - if err = t.sockJSSession.Send(string(msg)); err != nil { - return err - } - return nil -} - -// SessionMap stores a map of all TerminalSession objects and a lock to avoid concurrent conflict -type SessionMap struct { - Sessions map[string]TerminalSession - Lock sync.RWMutex -} - -// Get return a given terminalSession by sessionId -func (sm *SessionMap) Get(sessionId string) TerminalSession { - sm.Lock.RLock() - defer sm.Lock.RUnlock() - return sm.Sessions[sessionId] -} - -// Set store a TerminalSession to SessionMap -func (sm *SessionMap) Set(sessionId string, session TerminalSession) { - sm.Lock.Lock() - defer sm.Lock.Unlock() - sm.Sessions[sessionId] = session -} - -// Close shuts down the SockJS connection and sends the status code and reason to the client -// Can happen if the process exits or if there is an error starting up the process -// For now the status code is unused and reason is shown to the user (unless "") -func (sm *SessionMap) Close(sessionId string, status uint32, reason string) { - sm.Lock.Lock() - defer sm.Lock.Unlock() - err := sm.Sessions[sessionId].sockJSSession.Close(status, reason) - if err != nil { - log.Println(err) - } - - delete(sm.Sessions, sessionId) -} - -var terminalSessions = SessionMap{Sessions: make(map[string]TerminalSession)} - -// handleTerminalSession is Called by net/http for any new /api/sockjs connections -func handleTerminalSession(session sockjs.Session) { - var ( - buf string - err error - msg TerminalMessage - terminalSession TerminalSession - ) - - if buf, err = session.Recv(); err != nil { - log.Printf("handleTerminalSession: can't Recv: %v", err) - return - } - - if err = json.Unmarshal([]byte(buf), &msg); err != nil { - log.Printf("handleTerminalSession: can't UnMarshal (%v): %s", err, buf) - return - } - - if msg.Op != "bind" { - log.Printf("handleTerminalSession: expected 'bind' message, got: %s", buf) - return - } - - if terminalSession = terminalSessions.Get(msg.SessionID); terminalSession.id == "" { - log.Printf("handleTerminalSession: can't find session '%s'", msg.SessionID) - return - } - - terminalSession.sockJSSession = session - terminalSessions.Set(msg.SessionID, terminalSession) - terminalSession.bound <- nil -} - -// CreateAttachHandler is called from main for /api/sockjs -func CreateAttachHandler(path string) http.Handler { - return sockjs.NewHandler(path, sockjs.DefaultOptions, handleTerminalSession) -} - -// startProcess is called by handleAttach -// Executed cmd in the container specified in request and connects it up with the ptyHandler (a session) -func startProcess(k8sClient kubernetes.Interface, cfg *rest.Config, request *gin.Context, cmd []string, ptyHandler PtyHandler) error { - namespace := request.Query("namespace") - podName := request.Query("pod") - containerName := request.Query("container") - - req := k8sClient.CoreV1().RESTClient().Post(). - Resource("pods"). - Name(podName). - Namespace(namespace). - SubResource("exec") - - req.VersionedParams(&v1.PodExecOptions{ - Container: containerName, - Command: cmd, - Stdin: true, - Stdout: true, - Stderr: true, - TTY: true, - }, scheme.ParameterCodec) - - exec, err := remotecommand.NewSPDYExecutor(cfg, "POST", req.URL()) - if err != nil { - return err - } - - err = exec.Stream(remotecommand.StreamOptions{ - Stdin: ptyHandler, - Stdout: ptyHandler, - Stderr: ptyHandler, - TerminalSizeQueue: ptyHandler, - Tty: true, - }) - if err != nil { - return err - } - - return nil -} - -// genTerminalSessionId generates a random session ID string. The format is not really interesting. -// This ID is used to identify the session when the client opens the SockJS connection. -// Not the same as the SockJS session id! We can't use that as that is generated -// on the client side and we don't have it yet at this point. -func genTerminalSessionId() (string, error) { - bytes := make([]byte, 16) - if _, err := rand.Read(bytes); err != nil { - return "", err - } - id := make([]byte, hex.EncodedLen(len(bytes))) - hex.Encode(id, bytes) - return string(id), nil -} - -// isValidShell checks if the shell is an allowed one -func isValidShell(validShells []string, shell string) bool { - for _, validShell := range validShells { - if validShell == shell { - return true - } - } - return false -} - -// WaitForTerminal is called from apihandler.handleAttach as a goroutine -// Waits for the SockJS connection to be opened by the client the session to be bound in handleTerminalSession -func WaitForTerminal(k8sClient kubernetes.Interface, cfg *rest.Config, request *gin.Context, sessionId string) { - shell := request.Query("shell") - - select { - case <-terminalSessions.Get(sessionId).bound: - close(terminalSessions.Get(sessionId).bound) - - var err error - validShells := []string{"bash", "sh", "powershell", "cmd"} - - if isValidShell(validShells, shell) { - cmd := []string{shell} - err = startProcess(k8sClient, cfg, request, cmd, terminalSessions.Get(sessionId)) - } else { - // No shell given or it was not valid: try some shells until one succeeds or all fail - // FIXME: if the first shell fails then the first keyboard event is lost - for _, testShell := range validShells { - cmd := []string{testShell} - if err = startProcess(k8sClient, cfg, request, cmd, terminalSessions.Get(sessionId)); err == nil { - break - } - } - } - - if err != nil { - terminalSessions.Close(sessionId, 2, err.Error()) - return - } - - terminalSessions.Close(sessionId, 1, "Process exited") - } -} diff --git a/go.mod b/go.mod index ac463e7..26d2c71 100644 --- a/go.mod +++ b/go.mod @@ -20,8 +20,10 @@ require ( github.com/casbin/gorm-adapter/v3 v3.4.6 github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/didip/tollbooth v4.0.2+incompatible + github.com/golang/protobuf v1.4.3 // indirect github.com/google/uuid v1.3.0 github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible + github.com/json-iterator/go v1.1.11 // indirect github.com/kakuilan/kgo v0.1.8 github.com/lib/pq v1.10.4 github.com/mattn/go-isatty v0.0.13 // indirect @@ -30,7 +32,6 @@ require ( github.com/onsi/ginkgo v1.16.4 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pkg/errors v0.9.1 - github.com/prometheus/common v0.32.1 github.com/qiniu/go-sdk/v7 v7.11.0 github.com/robfig/cron/v3 v3.0.1 github.com/sirupsen/logrus v1.8.1 @@ -38,14 +39,9 @@ require ( github.com/swaggo/swag v1.7.6 github.com/tencentyun/cos-go-sdk-v5 v0.7.33 github.com/xuri/excelize/v2 v2.4.1 - go.uber.org/zap v1.19.0 golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 // indirect golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect - gopkg.in/igm/sockjs-go.v2 v2.1.0 + google.golang.org/protobuf v1.26.0-rc.1 // indirect gorm.io/driver/mysql v1.2.0 gorm.io/driver/postgres v1.2.3 - k8s.io/api v0.18.19 - k8s.io/apimachinery v0.18.19 - k8s.io/client-go v0.18.19 - k8s.io/kubectl v0.18.19 ) diff --git a/go.sum b/go.sum index b883e87..8381eb8 100644 --- a/go.sum +++ b/go.sum @@ -1,58 +1,12 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= -github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= @@ -60,79 +14,37 @@ github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 h1:5sXbqlSomvdjl github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/agiledragon/gomonkey/v2 v2.3.1 h1:k+UnUY0EMNYUFUAQVETGY9uUTxjMdnUkP0ARyJS1zzs= github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/aliyun/alibaba-cloud-sdk-go v1.61.1443 h1:rCVskInhkRcnsRgrvsZjmHRsjXxfQNdrHaU8CgV2vrg= github.com/aliyun/alibaba-cloud-sdk-go v1.61.1443/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU= github.com/aliyun/aliyun-oss-go-sdk v2.2.0+incompatible h1:ht2+VfbXtNLGhCsnTMc6/N26nSTBK6qdhktjYyjJQkk= github.com/aliyun/aliyun-oss-go-sdk v2.2.0+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA= github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/brianvoe/gofakeit/v6 v6.0.2 h1:MDvplMAKJMcKZDwQvsIbhT7BV/8UF/3EEy2n14ynUyA= github.com/brianvoe/gofakeit/v6 v6.0.2/go.mod h1:palrJUk4Fyw38zIFB/uBZqsgzW5VsNllhHKKwAebzew= github.com/casbin/casbin/v2 v2.37.4 h1:RWSKPjaZ8JlOBlcW1bI/FTII8OPxvQ9jVy9JwyNL6DQ= github.com/casbin/casbin/v2 v2.37.4/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= github.com/casbin/gorm-adapter/v3 v3.4.6 h1:JuLN3/CBTPPlvNyQqY3uXt4Zqnt+hs2sM353aCtLTP4= github.com/casbin/gorm-adapter/v3 v3.4.6/go.mod h1:6mIYgpByH/uSkfCv4G/vr/12cVZc3rXBQ9KrqS9oTUU= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/denisenkom/go-mssqldb v0.11.0 h1:9rHa233rhdOyrz2GcP9NM+gi2psgJZ4GWDpL/7ND8HI= github.com/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/didip/tollbooth v4.0.2+incompatible h1:fVSa33JzSz0hoh2NxpwZtksAzAgd7zjmGO20HCZtF4M= github.com/didip/tollbooth v4.0.2+incompatible/go.mod h1:A9b0665CE6l1KmzpDws2++elm/CsuWBMa5Jv4WY0PEY= -github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= -github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= -github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= -github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= -github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/gzip v0.0.3 h1:etUaeesHhEORpZMp18zoOhepboiWnFtXrBZxszWUn4k= github.com/gin-contrib/gzip v0.0.3/go.mod h1:YxxswVZIqOvcHEQpsSn+QF5guQtO1dCfy0shBPy4jFc= @@ -141,34 +53,17 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.7.4 h1:QmUZXrvJ9qZ3GfWvQ+2wnW/1ePrTEJqPKMYEU3lD/DM= github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= -github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/spec v0.20.3 h1:uH9RQ6vdyPSs2pSy9fL8QPspDF2AMIMPtmK5coSSjtQ= github.com/go-openapi/spec v0.20.3/go.mod h1:gG4F8wdEDN+YPBMVnzE85Rbhf+Th2DTvA9nFPQ5AYEg= -github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= @@ -193,94 +88,39 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= -github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8= -github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= -github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.1.0 h1:rVsPeBmXbYv4If/cumu1AzZPwV58q433hvONV1UEZoI= -github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q= -github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= @@ -340,38 +180,26 @@ github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI= github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA= github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kakuilan/kgo v0.1.8 h1:b9UfGYNbUpWjPheOEgu/MsWUVDNWbcSit6BbNsBAPl0= github.com/kakuilan/kgo v0.1.8/go.mod h1:S9driqss6OluzqiOfUx7xN8nw0H6bFu5v7c19P09RRc= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -385,13 +213,8 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= @@ -401,11 +224,6 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -420,26 +238,17 @@ github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSr github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= github.com/mssola/user_agent v0.5.3 h1:lBRPML9mdFuIZgI2cmlQ+atbpJdLdeVl2IDodjBR578= github.com/mssola/user_agent v0.5.3/go.mod h1:TTPno8LPY3wAIEKRpAtkdMT0f8SE24pLRGPahjCH4uw= -github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE= github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= @@ -448,33 +257,12 @@ github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT9 github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/qiniu/dyn v1.3.0/go.mod h1:E8oERcm8TtwJiZvkQPbcAh0RL8jO1G0VXJMW3FAWdkk= github.com/qiniu/go-sdk/v7 v7.11.0 h1:Cdx/1E3ybv0OFKnkGwoDN/t6bCCntjrWhwWuRaqI3XQ= github.com/qiniu/go-sdk/v7 v7.11.0/go.mod h1:btsaOc8CA3hdVloULfFdDgDc+g4f3TDZEFsDY0BLE+w= @@ -492,7 +280,6 @@ github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6po github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= @@ -500,24 +287,12 @@ github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9Nz github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -540,54 +315,30 @@ github.com/tencentyun/cos-go-sdk-v5 v0.7.33 h1:5jmJU7U/1nf/7ZPDkrUL8KlF1oDUzTHsd github.com/tencentyun/cos-go-sdk-v5 v0.7.33/go.mod h1:4E4+bQ2gBVJcgEC9Cufwylio4mXOct2iu05WjgEBx1o= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= -github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3 h1:EpI0bqf/eX9SdZDwlMmahKM+CDBgNbsXMhsN28XrM8o= github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= github.com/xuri/excelize/v2 v2.4.1 h1:veeeFLAJwsNEBPBlDepzPIYS1eLyBVcXNZUW79exZ1E= github.com/xuri/excelize/v2 v2.4.1/go.mod h1:rSu0C3papjzxQA3sdK8cU544TebhrPUoTOaGPIh0Q1A= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE= -go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -597,165 +348,61 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb h1:fqpd0EBDzlHRCjiphRR5Zo/RSWWQlWv34418dnEixWk= golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 h1:4CSI6oo7cOjJKajidEljs9h+uP0rRZBPPPhcCbj5mw8= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c h1:pkQiBZBvdos9qq4wBAHqlzuZHEXo07pqV06ef90u1WI= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 h1:kwrAHlwJ0DUBZwQ238v+Uod/3eZ8B2K5rYsUHBQvzmI= golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -763,63 +410,20 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M= golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -829,105 +433,29 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1 h1:7QnIQpGRHE5RnLKnESfDoxm2dTapTZua5a0kS0A+VXQ= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/igm/sockjs-go.v2 v2.1.0 h1:Ehqymxnfkkwi8R7SZIUARn77M0slA8vki0VgcfOdALw= -gopkg.in/igm/sockjs-go.v2 v2.1.0/go.mod h1:9l1o9p5TJvh2l+Q0EGE8USVB69QPfcvI7fR0HmbCk/8= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -953,44 +481,4 @@ gorm.io/gorm v1.22.3 h1:/JS6z+GStEQvJNW3t1FTwJwG/gZ+A7crFdRqtvG5ehA= gorm.io/gorm v1.22.3/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= gorm.io/plugin/dbresolver v1.1.0 h1:cegr4DeprR6SkLIQlKhJLYxH8muFbJ4SmnojXvoeb00= gorm.io/plugin/dbresolver v1.1.0/go.mod h1:tpImigFAEejCALOttyhWqsy4vfa2Uh/vAUVnL5IRF7Y= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.18.19 h1:mQfP1rIV3JWwyVQR/GtC07xn+YZ9gj4UTSQO8Og4T0A= -k8s.io/api v0.18.19/go.mod h1:lmViaHqL3es8JiaK3pCJMjBKm2CnzIcAXpHKifwbmAg= -k8s.io/apimachinery v0.18.19 h1:94g2jZjpfW2+qbphHe8WQIwj95qrjhrq8RU9jQknSgk= -k8s.io/apimachinery v0.18.19/go.mod h1:70HIRzSveORLKbatTlXzI2B2UUhbWzbq8Vqyf+HbdUQ= -k8s.io/cli-runtime v0.18.19/go.mod h1:SV1J1SLmt+GmZJqxm+1SeyX88Jhm088Lg61bQxSuemk= -k8s.io/client-go v0.18.19 h1:ym6jwLYcdWFKrIm0tU4Ct6evujnA8/OQTVdwLKJp5rY= -k8s.io/client-go v0.18.19/go.mod h1:lB+d4UqdzSjaU41VODLYm/oon3o05LAzsVpm6Me5XkY= -k8s.io/code-generator v0.18.19/go.mod h1:l5yJd8cLSvkIb0ZJMsQdWuDOx5rWfLNpgmHQyl3LmBE= -k8s.io/component-base v0.18.19/go.mod h1:nQMCdH6RaS/GD0J1YZqc5NInfCdknth4BwlAT5Mf7tA= -k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6 h1:Oh3Mzx5pJ+yIumsAD0MOECPVeXsVot0UkiaCGVyfGQY= -k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= -k8s.io/kubectl v0.18.19 h1:PYiptFCj9HBEyUo+mugBAOOZEzm+/WBt4iCVix8HrWg= -k8s.io/kubectl v0.18.19/go.mod h1:ZA3tS9BFS5C5aOSTy8JdvaXJ530zZT430JaHqTD9S2w= -k8s.io/metrics v0.18.19/go.mod h1:hritKYFqFHBC/6lWW28NKuuanFZyYLJqzYe49JE6iGg= -k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU= -k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/structured-merge-diff/v3 v3.0.1 h1:ISORLGKzslMY5RWkCSGNy5uDb3OHyEkGEhuSATvSp3A= -sigs.k8s.io/structured-merge-diff/v3 v3.0.1/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= -vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI= diff --git a/kubeconfig b/kubeconfig deleted file mode 100644 index 39e55af..0000000 --- a/kubeconfig +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: v1 -clusters: - - cluster: - certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJWekNCL3FBREFnRUNBZ0VBTUFvR0NDcUdTTTQ5QkFNQ01DTXhJVEFmQmdOVkJBTU1HR3N6Y3kxelpYSjIKWlhJdFkyRkFNVFl6T1RNNE1USXlNekFlRncweU1URXlNVE13TnpRd01qTmFGdzB6TVRFeU1URXdOelF3TWpOYQpNQ014SVRBZkJnTlZCQU1NR0dzemN5MXpaWEoyWlhJdFkyRkFNVFl6T1RNNE1USXlNekJaTUJNR0J5cUdTTTQ5CkFnRUdDQ3FHU000OUF3RUhBMElBQkJGRVlyNnlEbWpIK1lUcGNndk9zcE50azg5bHpGbGwzRkI1NkRFY3FyajIKMDNKamIyOFNaZDNPaWl6YmlGam45UG9yVU8rOXRsVGtFd0gyLzZ1WlRMbWpJekFoTUE0R0ExVWREd0VCL3dRRQpBd0lDcERBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUFvR0NDcUdTTTQ5QkFNQ0EwZ0FNRVVDSUdVYmFhR2RVS2tECms5VWx6L01TVU0zalM5KzFheXMzTUFPMS9OcC9CSU01QWlFQXZZUnpYd0dPZVdLTXFncHF3RmE5MGY4Y1I1bWEKazE1cmFBZnc2bTlCeDk4PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== - server: https://103.145.39.46:6443 - name: default -contexts: - - context: - cluster: default - user: default - name: default -current-context: default -kind: Config -preferences: {} -users: - - name: default - user: - password: 9eaf2a61260c20233484ed2af84c1ef9 - username: admin \ No newline at end of file diff --git a/main.go b/main.go index 4b6c36e..ccefcdf 100644 --- a/main.go +++ b/main.go @@ -1,8 +1,6 @@ package main import ( - "context" - "pandax/apps/devops/services/k8s/Init" "pandax/apps/job/jobs" "pandax/base/config" "pandax/base/ctx" @@ -15,7 +13,6 @@ import ( func main() { global.Db = starter.GormInit(config.Conf.Server.DbType) initialize.InitTable() - Init.GetK8sClient(context.Background(), "./kubeconfig") // gin后置 函数 ctx.UseAfterHandlerInterceptor(middleware.OperationHandler) // gin前置 函数