package cmd import ( "fmt" "os" "path/filepath" "sort" "github.com/kubeshark/kubeshark/config" "github.com/kubeshark/kubeshark/kubernetes" "github.com/kubeshark/kubeshark/misc" "github.com/kubeshark/kubeshark/utils" "github.com/otiai10/copy" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) var helmChartCmd = &cobra.Command{ Use: "helm-chart", Short: "Generate Helm chart of Kubeshark", RunE: func(cmd *cobra.Command, args []string) error { runHelmChart() return nil }, } // Maintainer describes a Chart maintainer. type Maintainer struct { // Name is a user name or organization name Name string `json:"name,omitempty"` // Email is an optional email address to contact the named maintainer Email string `json:"email,omitempty"` // URL is an optional URL to an address for the named maintainer URL string `json:"url,omitempty"` } // Metadata for a Chart file. This models the structure of a Chart.yaml file. type Metadata struct { // The name of the chart. Required. Name string `json:"name,omitempty"` // The URL to a relevant project page, git repo, or contact person Home string `json:"home,omitempty"` // Source is the URL to the source code of this chart Sources []string `json:"sources,omitempty"` // A SemVer 2 conformant version string of the chart. Required. Version string `json:"version,omitempty"` // A one-sentence description of the chart Description string `json:"description,omitempty"` // A list of string keywords Keywords []string `json:"keywords,omitempty"` // A list of name and URL/email address combinations for the maintainer(s) Maintainers []*Maintainer `json:"maintainers,omitempty"` // The URL to an icon file. Icon string `json:"icon,omitempty"` // The API Version of this chart. Required. APIVersion string `json:"apiVersion,omitempty"` // The condition to check to enable chart Condition string `json:"condition,omitempty"` // The tags to check to enable chart Tags string `json:"tags,omitempty"` // The version of the application enclosed inside of this chart. AppVersion string `json:"appVersion,omitempty"` // Whether or not this chart is deprecated Deprecated bool `json:"deprecated,omitempty"` // Annotations are additional mappings uninterpreted by Helm, // made available for inspection by other applications. Annotations map[string]string `json:"annotations,omitempty"` // KubeVersion is a SemVer constraint specifying the version of Kubernetes required. KubeVersion string `json:"kubeVersion,omitempty"` // Dependencies are a list of dependencies for a chart. Dependencies []*Dependency `json:"dependencies,omitempty"` // Specifies the chart type: application or library Type string `json:"type,omitempty"` } // Dependency describes a chart upon which another chart depends. // // Dependencies can be used to express developer intent, or to capture the state // of a chart. type Dependency struct { // Name is the name of the dependency. // // This must mach the name in the dependency's Chart.yaml. Name string `json:"name"` // Version is the version (range) of this chart. // // A lock file will always produce a single version, while a dependency // may contain a semantic version range. Version string `json:"version,omitempty"` // The URL to the repository. // // Appending `index.yaml` to this string should result in a URL that can be // used to fetch the repository index. Repository string `json:"repository"` // A yaml path that resolves to a boolean, used for enabling/disabling charts (e.g. subchart1.enabled ) Condition string `json:"condition,omitempty"` // Tags can be used to group charts for enabling/disabling together Tags []string `json:"tags,omitempty"` // Enabled bool determines if chart should be loaded Enabled bool `json:"enabled,omitempty"` // ImportValues holds the mapping of source values to parent key to be imported. Each item can be a // string or pair of child/parent sublist items. ImportValues []interface{} `json:"import-values,omitempty"` // Alias usable alias to be used for the chart Alias string `json:"alias,omitempty"` } func init() { rootCmd.AddCommand(helmChartCmd) } func runHelmChart() { namespace, serviceAccount, clusterRole, clusterRoleBinding, hubPod, hubService, frontPod, frontService, workerDaemonSet, err := generateManifests() if err != nil { log.Error().Err(err).Send() return } err = dumpHelmChart(map[string]interface{}{ "00-namespace.yaml": namespace, "01-service-account.yaml": serviceAccount, "02-cluster-role.yaml": clusterRole, "03-cluster-role-binding.yaml": clusterRoleBinding, "04-hub-pod.yaml": hubPod, "05-hub-service.yaml": hubService, "06-front-pod.yaml": frontPod, "07-front-service.yaml": frontService, "08-worker-daemon-set.yaml": workerDaemonSet, }) if err != nil { log.Error().Err(err).Send() return } } func dumpHelmChart(objects map[string]interface{}) error { folder := filepath.Join(".", "helm-chart") templatesFolder := filepath.Join(folder, "templates") err := os.MkdirAll(templatesFolder, os.ModePerm) if err != nil { return err } // Sort by filenames filenames := make([]string, 0) for filename := range objects { filenames = append(filenames, filename) } sort.Strings(filenames) // Generate templates for _, filename := range filenames { manifest, err := utils.PrettyYamlOmitEmpty(objects[filename]) if err != nil { return err } path := filepath.Join(templatesFolder, filename) err = os.WriteFile(path, []byte(manifest), 0644) if err != nil { return err } log.Info().Msgf("Helm chart template generated: %s", path) } // Copy LICENSE licenseSrcPath := filepath.Join(".", "LICENSE") licenseDstPath := filepath.Join(folder, "LICENSE") err = copy.Copy(licenseSrcPath, licenseDstPath) if err != nil { log.Warn().Err(err).Str("path", licenseSrcPath).Msg("Couldn't find the license:") } else { log.Info().Msgf("Helm chart license copied: %s", licenseDstPath) } // Generate Chart.yaml chartMetadata := Metadata{ APIVersion: "v2", Name: misc.Program, Description: misc.Description, Home: misc.Website, Sources: []string{"https://github.com/kubeshark/kubeshark/tree/master/helm-chart"}, Keywords: []string{ "kubeshark", "packet capture", "traffic capture", "traffic analyzer", "network sniffer", "observability", "devops", "microservice", "forensics", "api", }, Maintainers: []*Maintainer{ { Name: misc.Software, Email: misc.Email, URL: misc.Website, }, }, Version: misc.Ver, AppVersion: misc.Ver, KubeVersion: fmt.Sprintf(">= %s-0", kubernetes.MinKubernetesServerVersion), Type: "application", } chart, err := utils.PrettyYamlOmitEmpty(chartMetadata) if err != nil { return err } path := filepath.Join(folder, "Chart.yaml") err = os.WriteFile(path, []byte(chart), 0644) if err != nil { return err } log.Info().Msgf("Helm chart Chart.yaml generated: %s", path) // Generate values.yaml values, err := utils.PrettyYaml(config.Config) if err != nil { return err } path = filepath.Join(folder, "values.yaml") err = os.WriteFile(path, []byte(values), 0644) if err != nil { return err } log.Info().Msgf("Helm chart values.yaml generated: %s", path) return nil }