diff --git a/api/http/handler/system/version.go b/api/http/handler/system/version.go index 6ac244091..807b8f954 100644 --- a/api/http/handler/system/version.go +++ b/api/http/handler/system/version.go @@ -20,6 +20,7 @@ type versionResponse struct { LatestVersion string `json:"LatestVersion" example:"2.0.0"` ServerVersion string + ServerEdition string `json:"ServerEdition" example:"CE/EE"` DatabaseVersion string Build BuildInfo } @@ -48,6 +49,7 @@ func (handler *Handler) version(w http.ResponseWriter, r *http.Request) { result := &versionResponse{ ServerVersion: portainer.APIVersion, DatabaseVersion: portainer.APIVersion, + ServerEdition: portainer.Edition.GetEditionLabel(), Build: BuildInfo{ BuildNumber: build.BuildNumber, ImageTag: build.ImageTag, diff --git a/api/http/handler/system/version_test.go b/api/http/handler/system/version_test.go new file mode 100644 index 000000000..47a748bf3 --- /dev/null +++ b/api/http/handler/system/version_test.go @@ -0,0 +1,66 @@ +package system + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "net/http/httptest" + "testing" + + portainer "github.com/portainer/portainer/api" + "github.com/portainer/portainer/api/apikey" + "github.com/portainer/portainer/api/database/models" + "github.com/portainer/portainer/api/datastore" + "github.com/portainer/portainer/api/demo" + "github.com/portainer/portainer/api/http/security" + "github.com/portainer/portainer/api/jwt" + "github.com/stretchr/testify/assert" +) + +func Test_getSystemVersion(t *testing.T) { + is := assert.New(t) + + _, store := datastore.MustNewTestStore(t, true, true) + + // create version data + version := &models.Version{SchemaVersion: "2.20.0", Edition: 1} + err := store.Version().UpdateVersion(version) + is.NoError(err, "error creating version data") + + // create admin and standard user(s) + adminUser := &portainer.User{ID: 1, Username: "admin", Role: portainer.AdministratorRole} + err = store.User().Create(adminUser) + is.NoError(err, "error creating admin user") + + // setup services + jwtService, err := jwt.NewService("1h", store) + is.NoError(err, "Error initiating jwt service") + apiKeyService := apikey.NewAPIKeyService(store.APIKeyRepository(), store.User()) + requestBouncer := security.NewRequestBouncer(store, jwtService, apiKeyService) + + h := NewHandler(requestBouncer, &portainer.Status{}, &demo.Service{}, store, nil) + + // generate standard and admin user tokens + jwt, _ := jwtService.GenerateToken(&portainer.TokenData{ID: adminUser.ID, Username: adminUser.Username, Role: adminUser.Role}) + + t.Run("Display Edition", func(t *testing.T) { + + req := httptest.NewRequest(http.MethodGet, "/system/version", nil) + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", jwt)) + + rr := httptest.NewRecorder() + h.ServeHTTP(rr, req) + + is.Equal(http.StatusOK, rr.Code) + + body, err := io.ReadAll(rr.Body) + is.NoError(err, "ReadAll should not return error") + + var resp versionResponse + err = json.Unmarshal(body, &resp) + is.NoError(err, "response should be list json") + + is.Equal("CE", resp.ServerEdition, "Edition is not expected") + }) +} diff --git a/api/portainer.go b/api/portainer.go index e0c311f23..721c44b83 100644 --- a/api/portainer.go +++ b/api/portainer.go @@ -2057,6 +2057,20 @@ const ( OperationIntegrationStoridgeAdmin Authorization = "IntegrationStoridgeAdmin" ) +// GetEditionLabel returns the portainer edition label +func (e SoftwareEdition) GetEditionLabel() string { + switch e { + case PortainerCE: + return "CE" + case PortainerBE: + return "BE" + case PortainerEE: + return "EE" + } + + return "CE" +} + const ( AzurePathContainerGroups = "/subscriptions/*/providers/Microsoft.ContainerInstance/containerGroups" AzurePathContainerGroup = "/subscriptions/*/resourceGroups/*/providers/Microsoft.ContainerInstance/containerGroups/*"