* fix: add tls when get repository index. Signed-off-by: joyceliu <joyceliu@yunify.com> * Update staging/src/kubesphere.io/utils/helm/repo_index.go Signed-off-by: hongming <coder.scala@gmail.com> * fix: add tls when get repository index. Signed-off-by: joyceliu <joyceliu@yunify.com> --------- Signed-off-by: joyceliu <joyceliu@yunify.com> Signed-off-by: hongming <coder.scala@gmail.com> Co-authored-by: joyceliu <joyceliu@yunify.com> Co-authored-by: hongming <coder.scala@gmail.com>
167 lines
4.8 KiB
Go
167 lines
4.8 KiB
Go
/*
|
|
* Please refer to the LICENSE file in the root directory of the project.
|
|
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
|
|
*/
|
|
|
|
package v1alpha1
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"text/template"
|
|
|
|
"github.com/emicklei/go-restful/v3"
|
|
"helm.sh/helm/v3/pkg/chart/loader"
|
|
"helm.sh/helm/v3/pkg/getter"
|
|
"helm.sh/helm/v3/pkg/registry"
|
|
corev1 "k8s.io/api/core/v1"
|
|
"k8s.io/apimachinery/pkg/types"
|
|
corev1alpha1 "kubesphere.io/api/core/v1alpha1"
|
|
runtimeclient "sigs.k8s.io/controller-runtime/pkg/client"
|
|
|
|
"kubesphere.io/kubesphere/pkg/api"
|
|
)
|
|
|
|
var caTemplate = "{{ .TempDIR }}/repository/{{ .RepositoryName }}/ssl/ca.crt"
|
|
|
|
type handler struct {
|
|
cache runtimeclient.Reader
|
|
}
|
|
|
|
func (h *handler) ListFiles(request *restful.Request, response *restful.Response) {
|
|
extensionVersion := corev1alpha1.ExtensionVersion{}
|
|
if err := h.cache.Get(request.Request.Context(), types.NamespacedName{Name: request.PathParameter("version")}, &extensionVersion); err != nil {
|
|
api.HandleError(response, request, err)
|
|
return
|
|
}
|
|
|
|
if extensionVersion.Spec.ChartDataRef != nil {
|
|
configMap := &corev1.ConfigMap{}
|
|
if err := h.cache.Get(request.Request.Context(), types.NamespacedName{Namespace: extensionVersion.Spec.ChartDataRef.Namespace, Name: extensionVersion.Spec.ChartDataRef.Name}, configMap); err != nil {
|
|
api.HandleInternalError(response, request, err)
|
|
return
|
|
}
|
|
data := configMap.BinaryData[extensionVersion.Spec.ChartDataRef.Key]
|
|
if data == nil {
|
|
response.WriteEntity([]interface{}{})
|
|
return
|
|
}
|
|
files, err := loader.LoadArchiveFiles(bytes.NewReader(data))
|
|
if err != nil {
|
|
api.HandleInternalError(response, request, err)
|
|
return
|
|
}
|
|
response.WriteEntity(files)
|
|
return
|
|
}
|
|
|
|
chartURL, err := url.Parse(extensionVersion.Spec.ChartURL)
|
|
if err != nil {
|
|
api.HandleInternalError(response, request, err)
|
|
return
|
|
}
|
|
|
|
repo := &corev1alpha1.Repository{}
|
|
if extensionVersion.Spec.Repository != "" {
|
|
if err := h.cache.Get(request.Request.Context(), types.NamespacedName{Name: extensionVersion.Spec.Repository}, repo); err != nil {
|
|
api.HandleInternalError(response, request, err)
|
|
return
|
|
}
|
|
}
|
|
|
|
var chartGetter getter.Getter
|
|
switch chartURL.Scheme {
|
|
case registry.OCIScheme:
|
|
opts := make([]getter.Option, 0)
|
|
if extensionVersion.Spec.Repository != "" {
|
|
opts = append(opts, getter.WithInsecureSkipVerifyTLS(repo.Spec.Insecure))
|
|
}
|
|
if repo.Spec.BasicAuth != nil {
|
|
opts = append(opts, getter.WithBasicAuth(repo.Spec.BasicAuth.Username, repo.Spec.BasicAuth.Password))
|
|
}
|
|
chartGetter, err = getter.NewOCIGetter(opts...)
|
|
if err != nil {
|
|
api.HandleInternalError(response, request, fmt.Errorf("failed to create chart getter: %v", err))
|
|
return
|
|
}
|
|
case "http", "https":
|
|
opts := make([]getter.Option, 0)
|
|
if chartURL.Scheme == "https" && extensionVersion.Spec.Repository != "" {
|
|
opts = append(opts, getter.WithInsecureSkipVerifyTLS(repo.Spec.Insecure))
|
|
}
|
|
if repo.Spec.CABundle != "" {
|
|
caFile, err := storeCAFile(repo.Spec.CABundle, repo.Name)
|
|
if err != nil {
|
|
api.HandleInternalError(response, request, fmt.Errorf("failed to store CABundle to local file: %s", err))
|
|
return
|
|
}
|
|
opts = append(opts, getter.WithTLSClientConfig("", "", caFile))
|
|
}
|
|
if repo.Spec.BasicAuth != nil {
|
|
opts = append(opts, getter.WithBasicAuth(repo.Spec.BasicAuth.Username, repo.Spec.BasicAuth.Password))
|
|
}
|
|
chartGetter, err = getter.NewHTTPGetter(opts...)
|
|
if err != nil {
|
|
api.HandleInternalError(response, request, fmt.Errorf("failed to create chart getter: %v", err))
|
|
return
|
|
}
|
|
default:
|
|
api.HandleInternalError(response, request, fmt.Errorf("cannot support chartURL %s, it's schame should be: oci,http,https", extensionVersion.Spec.ChartURL))
|
|
return
|
|
}
|
|
|
|
data, err := chartGetter.Get(extensionVersion.Spec.ChartURL)
|
|
if err != nil {
|
|
api.HandleInternalError(response, request, err)
|
|
return
|
|
}
|
|
|
|
files, err := loader.LoadArchiveFiles(data)
|
|
if err != nil {
|
|
api.HandleInternalError(response, request, err)
|
|
return
|
|
}
|
|
|
|
_ = response.WriteEntity(files)
|
|
}
|
|
|
|
// storeCAFile in local file from caTemplate.
|
|
func storeCAFile(caBundle string, repoName string) (string, error) {
|
|
var buff = &bytes.Buffer{}
|
|
tmpl, err := template.New("repositoryCABundle").Parse(caTemplate)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if err := tmpl.Execute(buff, map[string]string{
|
|
"TempDIR": os.TempDir(),
|
|
"RepositoryName": repoName,
|
|
}); err != nil {
|
|
return "", err
|
|
}
|
|
caFile := buff.String()
|
|
if _, err := os.Stat(filepath.Dir(caFile)); err != nil {
|
|
if !os.IsNotExist(err) {
|
|
return "", err
|
|
}
|
|
|
|
if err := os.MkdirAll(filepath.Dir(caFile), os.ModePerm); err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
|
|
data, err := base64.StdEncoding.DecodeString(caBundle)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if err := os.WriteFile(caFile, data, os.ModePerm); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return caFile, nil
|
|
}
|