diff --git a/glide.yaml b/glide.yaml index c843cb9..5d1c86a 100644 --- a/glide.yaml +++ b/glide.yaml @@ -3,8 +3,9 @@ import: - package: github.com/emicklei/go-restful version: ~1.2.0 subpackages: - - swagger - log +- package: github.com/emicklei/go-restful-swagger12 + version: ~1.0.1 - package: github.com/Sirupsen/logrus version: ~0.10.0 - package: k8s.io/helm diff --git a/internal/client/tiller-client.go b/internal/client/tiller-client.go index def12ab..87883c7 100644 --- a/internal/client/tiller-client.go +++ b/internal/client/tiller-client.go @@ -59,6 +59,17 @@ func (tc *TillerClient) InstallRelease(req *tiller.InstallReleaseRequest) (res * return } +// UpdateRelease updates a release +func (tc *TillerClient) UpdateRelease(req *tiller.UpdateReleaseRequest) (res *tiller.UpdateReleaseResponse, err error) { + tc.execute(func(rsc tiller.ReleaseServiceClient) { + res, err = rsc.UpdateRelease(tc.context, req) + if err != nil { + log.Debug("unable to update release") + } + }) + return +} + // UninstallRelease uninstalls a release func (tc *TillerClient) UninstallRelease(req *tiller.UninstallReleaseRequest) (res *tiller.UninstallReleaseResponse, err error) { tc.execute(func(rsc tiller.ReleaseServiceClient) { diff --git a/internal/controller/release.go b/internal/controller/release.go index c6d8a54..d142d08 100644 --- a/internal/controller/release.go +++ b/internal/controller/release.go @@ -8,15 +8,10 @@ import ( tiller "k8s.io/helm/pkg/proto/hapi/services" "fmt" + "github.com/AcalephStorage/rudder/internal/client" ) -// GetReleaseResponse contains the response for requesting Release information -type GetReleaseResponse struct { - Content *tiller.GetReleaseContentResponse `json:"content"` - Status *tiller.GetReleaseStatusResponse `json:"status"` -} - // ReleaseController handles helm release related operations type ReleaseController struct { tillerClient *client.TillerClient @@ -82,6 +77,46 @@ func (rc *ReleaseController) InstallRelease(name, namespace, repo, chart, versio return res, nil } +// UpdateRelease updates a release with the provided chart +func (rc *ReleaseController) UpdateRelease(name, repo, chart, version string, values map[string]interface{}) (*tiller.UpdateReleaseResponse, error) { + chartDetails, err := rc.repoController.ChartDetails(repo, chart, version) + if err != nil { + log.WithError(err).Error("unable to get chart details") + return nil, err + } + tarball := chartDetails.ChartFile + + inChart, err := chartutil.LoadFile(tarball) + if err != nil { + log.WithError(err).Error("unable to load chart details") + return nil, err + } + raw, _ := yaml.Marshal(values) + + inValues := make(map[string]*hapi_chart.Value) + for k, v := range values { + inValues[k] = &hapi_chart.Value{Value: fmt.Sprintf("%v", v)} + } + + config := &hapi_chart.Config{ + Raw: string(raw), + Values: inValues, + } + + req := &tiller.UpdateReleaseRequest{ + Name: name, + Chart: inChart, + Values: config, + } + + res, err := rc.tillerClient.UpdateRelease(req) + if err != nil { + log.WithError(err).Error("unable to update release") + return nil, err + } + return res, nil +} + // UninstallRelease uninstall a release func (rc *ReleaseController) UninstallRelease(releaseName string, purge bool) (*tiller.UninstallReleaseResponse, error) { req := &tiller.UninstallReleaseRequest{ @@ -98,7 +133,7 @@ func (rc *ReleaseController) UninstallRelease(releaseName string, purge bool) (* } // GetRelease returns the release details -func (rc *ReleaseController) GetRelease(name string, version int32) (*GetReleaseResponse, error) { +func (rc *ReleaseController) GetRelease(name string, version int32) (*tiller.GetReleaseContentResponse, error) { req := &tiller.GetReleaseContentRequest{ Name: name, Version: version, @@ -108,18 +143,19 @@ func (rc *ReleaseController) GetRelease(name string, version int32) (*GetRelease log.WithError(err).Error("unable to get release content") return nil, err } + return content, nil +} - req2 := &tiller.GetReleaseStatusRequest{ +// GetReleaseStatus returns the release status +func (rc *ReleaseController) GetReleaseStatus(name string, version int32) (*tiller.GetReleaseStatusResponse, error) { + req := &tiller.GetReleaseStatusRequest{ Name: name, Version: version, } - status, err := rc.tillerClient.GetReleaseStatus(req2) + status, err := rc.tillerClient.GetReleaseStatus(req) if err != nil { log.WithError(err).Error("unable to get release status") return nil, err } - return &GetReleaseResponse{ - Content: content, - Status: status, - }, nil + return status, nil } diff --git a/internal/resource/release.go b/internal/resource/release.go index 5afb01f..9ef1115 100644 --- a/internal/resource/release.go +++ b/internal/resource/release.go @@ -37,8 +37,10 @@ var ( var ( errFailToListReleases = restful.NewError(http.StatusBadRequest, "unable to get list of releases") errFailToInstallRelease = restful.NewError(http.StatusInternalServerError, "unable to install releases") + errFailToUpdateRelease = restful.NewError(http.StatusInternalServerError, "unable to update releases") errFailtToUninstallRelease = restful.NewError(http.StatusInternalServerError, "unable to uninstall releases") - errFailToGetRelease = restful.NewError(http.StatusInternalServerError, "unable to get release content and status") + errFailToGetRelease = restful.NewError(http.StatusInternalServerError, "unable to get release content") + errFailToGetReleaseStatus = restful.NewError(http.StatusInternalServerError, "unable to get release status") ) // InstallReleaseRequest is the request body needed for installing a new release @@ -51,6 +53,15 @@ type InstallReleaseRequest struct { Values map[string]interface{} `json:"values"` } +// UpdateReleaseRequest is the request body needed for updating an existing release +type UpdateReleaseRequest struct { + Name string `json:"name"` + Repo string `json:"repo"` + Chart string `json:"chart"` + Version string `json:"version"` + Values map[string]interface{} `json:"values"` +} + // ReleaseResource represents helm releases type ReleaseResource struct { controller *controller.ReleaseController @@ -89,6 +100,13 @@ func (rr *ReleaseResource) Register(container *restful.Container) { Reads(InstallReleaseRequest{}). Writes(tiller.InstallReleaseResponse{})) + // PUT /api/v1/releases + ws.Route(ws.PUT("").To(rr.updateRelease). + Doc("update release. defaults: version=latest."). + Operation("udpateRelease"). + Reads(InstallReleaseRequest{}). + Writes(tiller.UpdateReleaseResponse{})) + // DELETE /api/v1/releases/{release} ws.Route(ws.DELETE("/{release}").To(rr.uninstallRelease). Doc("uninstall release"). @@ -102,7 +120,15 @@ func (rr *ReleaseResource) Register(container *restful.Container) { Operation("getRelease"). Param(ws.PathParameter("release", "the release name")). Param(ws.PathParameter("version", "the release version")). - Writes(controller.GetReleaseResponse{})) + Writes(tiller.GetReleaseContentResponse{})) + + // GET /api/v1/releases/{release}/{version} + ws.Route(ws.GET("/{release}/{version}/status").To(rr.getReleaseStatus). + Doc("get release status"). + Operation("getReleaseStatus"). + Param(ws.PathParameter("release", "the release name")). + Param(ws.PathParameter("version", "the release version")). + Writes(tiller.GetReleaseStatusResponse{})) container.Add(ws) @@ -171,6 +197,25 @@ func (rr *ReleaseResource) installRelease(req *restful.Request, res *restful.Res } } +// updateRelease updates the release with the provided chart +func (rr *ReleaseResource) updateRelease(req *restful.Request, res *restful.Response) { + in := UpdateReleaseRequest{ + Version: "latest", + } + if err := req.ReadEntity(&in); err != nil { + errorResponse(res, errFailToReadResponse) + return + } + out, err := rr.controller.UpdateRelease(in.Name, in.Repo, in.Chart, in.Version, in.Values) + if err != nil { + errorResponse(res, errFailToUpdateRelease) + return + } + if err := res.WriteEntity(out); err != nil { + errorResponse(res, errFailToWriteResponse) + } +} + // uninstallRelease removes the release from the list of releases func (rr *ReleaseResource) uninstallRelease(req *restful.Request, res *restful.Response) { releaseName := req.PathParameter("release") @@ -200,17 +245,23 @@ func (rr *ReleaseResource) getRelease(req *restful.Request, res *restful.Respons if err := res.WriteEntity(out); err != nil { errorResponse(res, errFailToWriteResponse) } - } -// GET api/v1/releases/:name/:version/:status {create request body} -func (rr *ReleaseResource) releaseStatus(req *restful.Request, res *restful.Response) { - // TODO -} +// getReleaseStatus returns the status of the provided release +func (rr *ReleaseResource) getReleaseStatus(req *restful.Request, res *restful.Response) { + name := req.PathParameter("release") + versionRaw := req.PathParameter("version") + version := util.ToInt32(versionRaw) -// PUT api/v1/releases {request body passed} -func (rr *ReleaseResource) updateRelease(req *restful.Request, res *restful.Response) { - // TODO + out, err := rr.controller.GetReleaseStatus(name, version) + if err != nil { + errorResponse(res, errFailToGetReleaseStatus) + return + } + + if err := res.WriteEntity(out); err != nil { + errorResponse(res, errFailToWriteResponse) + } } // POST ??? I DUNNOT KNOW