return readme

This commit is contained in:
GLYASAI 2021-04-19 11:52:52 +08:00
parent 769dd3d8ae
commit 0c23b0ba30
16 changed files with 115 additions and 53 deletions

View File

@ -136,6 +136,7 @@ func (v2 *V2) tenantNameRouter() chi.Router {
r.Get("/event", controller.GetManager().Event)
r.Get("/chargesverify", controller.ChargesVerifyController)
//tenant app
r.Get("/pods/{pod_name}", controller.GetManager().PodDetail)
r.Post("/apps", controller.GetManager().CreateApp)
r.Post("/batch_create_apps", controller.GetManager().BatchCreateApp)
r.Get("/apps", controller.GetManager().ListApps)

View File

@ -88,8 +88,8 @@ func Pods(w http.ResponseWriter, r *http.Request) {
// PodDetail -
func (p *PodController) PodDetail(w http.ResponseWriter, r *http.Request) {
podName := chi.URLParam(r, "pod_name")
serviceID := r.Context().Value(middleware.ContextKey("service_id")).(string)
pd, err := handler.GetPodHandler().PodDetail(serviceID, podName)
namespace := r.Context().Value(middleware.ContextKey("tenant_id")).(string)
pd, err := handler.GetPodHandler().PodDetail(namespace, podName)
if err != nil {
logrus.Errorf("error getting pod detail: %v", err)
if err == server.ErrPodNotFound {

View File

@ -304,9 +304,37 @@ func (a *ApplicationAction) getHelmAppStatus(ctx context.Context, app *dbmodel.A
return nil, errors.WithStack(err)
}
phase := string(v1alpha1.HelmAppStatusPhaseDetecting)
if string(helmApp.Status.Phase) != "" {
phase = string(helmApp.Status.Phase)
}
labelSelector := labels.FormatLabels(map[string]string{
"app.kubernetes.io/instance": app.AppName,
"app.kubernetes.io/managed-by": "Helm",
})
podList, err := a.kubeClient.CoreV1().Pods(app.TenantID).List(ctx, metav1.ListOptions{
LabelSelector: labelSelector,
})
if err != nil {
return nil, err
}
var cpu, memory int64
for _, pod := range podList.Items {
for _, c := range pod.Spec.Containers {
cpu += c.Resources.Requests.Cpu().MilliValue()
memory += c.Resources.Limits.Memory().Value() / 1024 / 1024
}
}
return &model.AppStatus{
Phase: string(helmApp.Status.Phase),
Status: string(helmApp.Status.Status),
Phase: phase,
ValuesTemplate: helmApp.Status.ValuesTemplate,
Cpu: cpu,
Memory: memory,
Readme: helmApp.Status.Readme,
}, nil
}
@ -379,7 +407,7 @@ func (a *ApplicationAction) ListServices(ctx context.Context, app *dbmodel.Appli
// list services
labelSelector := labels.FormatLabels(map[string]string{
"app.kubernetes.io/name": app.AppName,
"app.kubernetes.io/instance": app.AppName,
"app.kubernetes.io/managed-by": "Helm",
})
serviceList, err := a.kubeClient.CoreV1().Services(app.TenantID).List(nctx, metav1.ListOptions{

View File

@ -14,8 +14,8 @@ type PodAction struct {
}
// PodDetail -
func (p *PodAction) PodDetail(serviceID, podName string) (*pb.PodDetail, error) {
pd, err := p.statusCli.GetPodDetail(serviceID, podName)
func (p *PodAction) PodDetail(namespace, podName string) (*pb.PodDetail, error) {
pd, err := p.statusCli.GetPodDetail(namespace, podName)
if err != nil {
if strings.Contains(err.Error(), server.ErrPodNotFound.Error()) {
return nil, server.ErrPodNotFound

View File

@ -7,7 +7,7 @@ import (
// PodHandler defines handler methods about k8s pods.
type PodHandler interface {
PodDetail(serviceID, podName string) (*pb.PodDetail, error)
PodDetail(namespace, podName string) (*pb.PodDetail, error)
}
// NewPodHandler creates a new PodHandler.

View File

@ -16,6 +16,7 @@ type AppStatus struct {
Disk int64 `json:"disk"`
Phase string `json:"phase"`
ValuesTemplate string `json:"valuesTemplate"`
Readme string `json:"readme"`
}
// AppDetectProcess -

View File

@ -51,9 +51,7 @@ func main() {
//}
ctrl := helmapp.NewController(stopCh, restcfg, 5*time.Second, "/tmp/helm/repo/repositories.yaml", "/tmp/helm/cache")
if err = ctrl.Start(); err != nil {
logrus.Fatalf("start controller: %v", err)
}
ctrl.Start()
select {}
}

View File

@ -19,11 +19,6 @@
package server
import (
"os"
"os/signal"
"syscall"
"time"
"github.com/eapache/channels"
"github.com/goodrain/rainbond/cmd/worker/option"
"github.com/goodrain/rainbond/db"
@ -34,7 +29,6 @@ import (
"github.com/goodrain/rainbond/worker/appm"
"github.com/goodrain/rainbond/worker/appm/controller"
"github.com/goodrain/rainbond/worker/appm/store"
"github.com/goodrain/rainbond/worker/controllers/helmapp"
"github.com/goodrain/rainbond/worker/discover"
"github.com/goodrain/rainbond/worker/gc"
"github.com/goodrain/rainbond/worker/master"
@ -42,6 +36,9 @@ import (
"github.com/goodrain/rainbond/worker/server"
"github.com/sirupsen/logrus"
"k8s.io/client-go/kubernetes"
"os"
"os/signal"
"syscall"
)
//Run start run
@ -132,9 +129,10 @@ func Run(s *option.Worker) error {
}
defer exporterManager.Stop()
stopCh := make(chan struct{})
ctrl := helmapp.NewController(stopCh, restConfig, 5*time.Second, "/tmp/helm/repo/repositories.yaml", "/tmp/helm/cache")
go ctrl.Start()
//stopCh := make(chan struct{})
//ctrl := helmapp.NewController(stopCh, restConfig, 5*time.Second, "/tmp/helm/repo/repositories.yaml", "/tmp/helm/cache")
//go ctrl.Start()
//defer close(stopCh)
logrus.Info("worker begin running...")

View File

@ -124,10 +124,10 @@ type HelmAppSpec struct {
Version string `json:"version"`
// The application revision.
Revision *int32 `json:"revision"`
Revision *int32 `json:"revision,omitempty"`
// The values.yaml of the helm app, encoded by base64.
Values string `json:"values"`
Values string `json:"values,omitempty"`
// The helm app store.
// TODO: validation. not null
@ -170,6 +170,8 @@ type HelmAppStatus struct {
CurrentRevision string `json:"currentRevision,omitempty"`
ValuesTemplate string `json:"valuesTemplate,omitempty"`
Readme string `json:"readme,omitempty"`
}
// +genclient

View File

@ -73,6 +73,7 @@ var rc2RecordType = map[string]string{
type Storer interface {
Start() error
Ready() bool
GetPod(namespace, name string) (*corev1.Pod, error)
RegistAppService(*v1.AppService)
GetAppService(serviceID string) *v1.AppService
UpdateGetAppService(serviceID string) *v1.AppService
@ -880,6 +881,10 @@ func (a *appRuntimeStore) RegistAppService(app *v1.AppService) {
logrus.Debugf("current have %d app after add \n", a.appCount)
}
func (a *appRuntimeStore) GetPod(namespace, name string) (*corev1.Pod, error) {
return a.listers.Pod.Pods(namespace).Get(name)
}
//DeleteAppService delete cache app service
func (a *appRuntimeStore) DeleteAppService(app *v1.AppService) {
//a.appServices.Delete(v1.GetCacheKeyOnlyServiceID(app.ServiceID))

View File

@ -75,15 +75,7 @@ func (c *ControlLoop) run(obj interface{}) {
}
func (c *ControlLoop) Reconcile(helmApp *v1alpha1.HelmApp) error {
logrus.Debugf("HelmApp Received: %s", k8sutil.ObjKey(helmApp))
status := NewStatus(helmApp)
defer func() {
helmApp.Status = status.GetHelmAppStatus()
// TODO: handle the error
c.updateStatus(helmApp)
}()
logrus.Debugf("HelmApp Received: %s; phase: %s", k8sutil.ObjKey(helmApp), helmApp.Status.Phase)
appStore := helmApp.Spec.AppStore
app, err := helm.NewApp(helmApp.Name, helmApp.Namespace,
@ -95,6 +87,20 @@ func (c *ControlLoop) Reconcile(helmApp *v1alpha1.HelmApp) error {
return err
}
status, continu3 := NewStatus(helmApp)
defer func() {
helmApp.Status = status.GetHelmAppStatus()
s, _ := app.Status()
helmApp.Status.Status = v1alpha1.HelmAppStatusStatus(s)
// TODO: handle the error
c.updateStatus(helmApp)
}()
if !continu3 {
return nil
}
detector := NewDetector(helmApp, status, app, c.repo)
if err := detector.Detect(); err != nil {
// TODO: create event

View File

@ -46,6 +46,7 @@ func (d *Detector) Detect() error {
return err
}
d.status.UpdateConditionStatus(v1alpha1.HelmAppChartReady, corev1.ConditionTrue)
return nil
}
// check if the chart is valid
@ -56,11 +57,12 @@ func (d *Detector) Detect() error {
return err
}
d.status.UpdateConditionStatus(v1alpha1.HelmAppPreInstalled, corev1.ConditionTrue)
return nil
}
// parse chart
if !d.status.IsConditionTrue(v1alpha1.HelmAppChartParsed) {
values, err := d.app.ParseChart()
values, readme, err := d.app.ParseChart()
if err != nil {
d.status.UpdateCondition(v1alpha1.NewHelmAppCondition(
v1alpha1.HelmAppChartParsed, corev1.ConditionFalse, "ChartParsed", err.Error()))
@ -68,6 +70,7 @@ func (d *Detector) Detect() error {
}
d.status.UpdateConditionStatus(v1alpha1.HelmAppChartParsed, corev1.ConditionTrue)
d.status.ValuesTemplate = values
d.status.Readme = readme
}
return nil

View File

@ -7,7 +7,6 @@ import (
"os"
"path"
"path/filepath"
"strings"
"github.com/goodrain/rainbond/util/commonutil"
"github.com/pkg/errors"
@ -87,15 +86,23 @@ func (a *App) chart() string {
func (a *App) PreInstall() error {
var buf bytes.Buffer
if err := a.helm.PreInstall(a.templateName, a.namespace, a.Chart(), &buf); err != nil {
if err := a.helm.PreInstall(a.name, a.namespace, a.Chart(), &buf); err != nil {
return err
}
logrus.Infof("pre install: %s", buf.String())
return nil
}
func (a *App) Status() (string, error) {
release, err := a.helm.Status(a.name)
if err != nil {
return "", err
}
return string(release.Info.Status), nil
}
func (a *App) InstallOrUpdate() error {
err := a.helm.Status(a.name)
_, err := a.helm.Status(a.name)
if errors.Is(err, driver.ErrReleaseNotFound) {
b, err := base64.StdEncoding.DecodeString(a.encodedValues)
if err != nil {
@ -108,7 +115,7 @@ func (a *App) InstallOrUpdate() error {
}
var buf bytes.Buffer
if err := a.helm.Install(a.templateName, a.namespace, a.Chart(), values, &buf); err != nil {
if err := a.helm.Install(a.name, a.namespace, a.Chart(), values, &buf); err != nil {
return err
}
logrus.Infof("install: %s", buf.String())
@ -117,26 +124,38 @@ func (a *App) InstallOrUpdate() error {
return nil
}
func (a *App) ParseChart() (string, error) {
func (a *App) ParseChart() (string, string, error) {
var values string
err := filepath.Walk(a.chartDir, func(path string, info os.FileInfo, err error) error {
var readme string
err := filepath.Walk(a.chartDir, func(p string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
if p == a.chartDir {
return nil
}
if !strings.Contains(path, "values.yaml") {
if values != "" || readme != "" {
return filepath.SkipDir
}
if !info.IsDir() {
return nil
}
file, err := ioutil.ReadFile(path)
valuesFile := path.Join(p, "values.yaml")
valuesBytes, err := ioutil.ReadFile(valuesFile)
if err != nil {
return err
}
values = base64.StdEncoding.EncodeToString(file)
values = base64.StdEncoding.EncodeToString(valuesBytes)
readmeFile := path.Join(p, "README.md")
readmeBytes, err := ioutil.ReadFile(readmeFile)
if err != nil {
return err
}
readme = base64.StdEncoding.EncodeToString(readmeBytes)
return nil
})
return values, err
return values, readme, err
}

View File

@ -12,6 +12,7 @@ import (
"helm.sh/helm/v3/pkg/downloader"
"helm.sh/helm/v3/pkg/getter"
"helm.sh/helm/v3/pkg/kube"
"helm.sh/helm/v3/pkg/release"
"k8s.io/cli-runtime/pkg/genericclioptions"
)
@ -119,11 +120,11 @@ func (h *Helm) install(name, namespace, chart string, vals map[string]interface{
return err
}
func (h *Helm) Status(name string) error {
func (h *Helm) Status(name string) (*release.Release, error) {
// helm status RELEASE_NAME [flags]
client := action.NewStatus(h.cfg)
_, err := client.Run(name)
return err
rel, err := client.Run(name)
return rel, errors.Wrap(err, "helm status")
}
// checkIfInstallable validates if a chart can be installed

View File

@ -11,23 +11,27 @@ type Status struct {
}
// NewStatus creates a new helm app status.
func NewStatus(app *v1alpha1.HelmApp) *Status {
func NewStatus(app *v1alpha1.HelmApp) (*Status, bool) {
continu3 := true
idx, _ := app.Status.GetCondition(v1alpha1.HelmAppChartReady)
if idx == -1 {
app.Status.UpdateConditionStatus(v1alpha1.HelmAppChartReady, corev1.ConditionFalse)
continu3 = false
}
idx, _ = app.Status.GetCondition(v1alpha1.HelmAppPreInstalled)
if idx == -1 {
app.Status.UpdateConditionStatus(v1alpha1.HelmAppPreInstalled, corev1.ConditionFalse)
continu3 = false
}
idx, _ = app.Status.GetCondition(v1alpha1.HelmAppChartParsed)
if idx == -1 {
app.Status.UpdateConditionStatus(v1alpha1.HelmAppChartParsed, corev1.ConditionFalse)
continu3 = false
}
return &Status{
HelmAppStatus: app.Status,
values: app.Spec.Values,
}
}, continu3
}
func (s *Status) GetHelmAppStatus() v1alpha1.HelmAppStatus {

View File

@ -79,12 +79,8 @@ func (r *RuntimeServer) GetPodDetail(ctx context.Context, req *pb.GetPodDetailRe
return podDetail, nil
}
func (r *RuntimeServer) getPodByName(sid, name string) (*corev1.Pod, error) {
app := r.store.GetAppService(sid)
if app == nil {
return nil, ErrAppServiceNotFound
}
return app.GetPodsByName(name), nil
func (r *RuntimeServer) getPodByName(namespace, name string) (*corev1.Pod, error) {
return r.store.GetPod(namespace, name)
}
// GetPodEvents -