diff --git a/deploy/openshift/templates/monitoring/che-monitoring.yaml b/deploy/openshift/templates/monitoring/che-monitoring.yaml index df7dae75e1f..36def2ea01f 100644 --- a/deploy/openshift/templates/monitoring/che-monitoring.yaml +++ b/deploy/openshift/templates/monitoring/che-monitoring.yaml @@ -74,7 +74,7 @@ objects: deploymentconfig: grafana spec: containers: - - image: grafana/grafana + - image: grafana/grafana:6.6.2 imagePullPolicy: Always name: grafana ports: diff --git a/deploy/openshift/templates/monitoring/grafana-dashboards.yaml b/deploy/openshift/templates/monitoring/grafana-dashboards.yaml index 4f215ffa463..95445c7bf5a 100644 --- a/deploy/openshift/templates/monitoring/grafana-dashboards.yaml +++ b/deploy/openshift/templates/monitoring/grafana-dashboards.yaml @@ -3608,7 +3608,7 @@ data: "version": 1 } che-workspaces.json: |- - { + { "annotations": { "list": [ { @@ -3625,8 +3625,7 @@ data: "editable": true, "gnetId": null, "graphTooltip": 1, - "id": 2, - "iteration": 1574014597638, + "iteration": 1587125836872, "links": [], "panels": [ { @@ -3817,98 +3816,6 @@ data: ], "valueName": "current" }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "${datasource}", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 5, - "w": 6, - "x": 12, - "y": 17 - }, - "hiddenSeries": false, - "id": 110, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "sum(che_workspace_starting_attempts_total)", - "legendFormat": "Workspace start attempts", - "refId": "A" - }, - { - "expr": "che_workspace_starting_attempts_total{debug='true'}", - "legendFormat": "Workspace start attempts in start-debug mode", - "refId": "B" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Workspace start attempts", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": 0, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": 0, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } - }, { "collapsed": false, "datasource": "$datasource", @@ -3938,6 +3845,7 @@ data: "x": 0, "y": 7 }, + "hiddenSeries": false, "id": 36, "interval": "", "legend": { @@ -4037,6 +3945,7 @@ data: "x": 6, "y": 7 }, + "hiddenSeries": false, "id": 48, "interval": "", "legend": { @@ -4135,6 +4044,7 @@ data: "x": 12, "y": 7 }, + "hiddenSeries": false, "id": 6, "legend": { "avg": true, @@ -4225,6 +4135,7 @@ data: "x": 18, "y": 7 }, + "hiddenSeries": false, "id": 59, "legend": { "avg": true, @@ -4316,6 +4227,7 @@ data: "x": 0, "y": 12 }, + "hiddenSeries": false, "id": 44, "legend": { "avg": true, @@ -4408,6 +4320,7 @@ data: "x": 6, "y": 12 }, + "hiddenSeries": false, "id": 49, "legend": { "avg": true, @@ -4500,6 +4413,7 @@ data: "x": 12, "y": 12 }, + "hiddenSeries": false, "id": 8, "legend": { "avg": false, @@ -4590,6 +4504,7 @@ data: "x": 18, "y": 12 }, + "hiddenSeries": false, "id": 10, "legend": { "avg": true, @@ -4681,6 +4596,7 @@ data: "x": 0, "y": 17 }, + "hiddenSeries": false, "id": 62, "legend": { "avg": true, @@ -4773,6 +4689,7 @@ data: "x": 6, "y": 17 }, + "hiddenSeries": false, "id": 77, "legend": { "avg": false, @@ -4800,12 +4717,18 @@ data: "steppedLine": false, "targets": [ { - "expr": "sum(che_workspace_status)", + "expr": "che_workspace_total", "format": "time_series", "instant": false, + "interval": "", "intervalFactor": 1, - "legendFormat": "Number of Workspaces", + "legendFormat": "total", "refId": "A" + }, + { + "expr": "sum(che_workspace_status)", + "legendFormat": "status sum", + "refId": "B" } ], "thresholds": [], @@ -4851,6 +4774,98 @@ data: "alignLevel": null } }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${datasource}", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 17 + }, + "hiddenSeries": false, + "id": 110, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(che_workspace_starting_attempts_total)", + "legendFormat": "Workspace start attempts", + "refId": "A" + }, + { + "expr": "che_workspace_starting_attempts_total{debug='true'}", + "legendFormat": "Workspace start attempts in start-debug mode", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Workspace start attempts", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, { "collapsed": false, "datasource": "$datasource", @@ -4881,6 +4896,7 @@ data: "x": 0, "y": 23 }, + "hiddenSeries": false, "id": 78, "legend": { "avg": false, @@ -4985,6 +5001,7 @@ data: "x": 0, "y": 29 }, + "hiddenSeries": false, "id": 16, "legend": { "avg": false, @@ -5091,6 +5108,7 @@ data: "x": 0, "y": 37 }, + "hiddenSeries": false, "id": 105, "interval": "", "legend": { @@ -5179,6 +5197,7 @@ data: "x": 12, "y": 37 }, + "hiddenSeries": false, "id": 108, "interval": "", "legend": { @@ -9513,11 +9532,11 @@ data: } }, { - "datasource": "${datasource}", "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, + "datasource": "${datasource}", "fill": 1, "fillGradient": 0, "gridPos": { @@ -9578,22 +9597,22 @@ data: }, "yaxes": [ { + "decimals": 0, "format": "short", "label": null, "logBase": 1, "max": null, "min": 0, - "show": true, - "decimals": 0 + "show": true }, { + "decimals": 0, "format": "short", "label": null, "logBase": 1, "max": null, "min": 0, - "show": true, - "decimals": 0 + "show": true } ], "yaxis": { @@ -9673,12 +9692,16 @@ data: } ], "refresh": "15m", - "schemaVersion": 19, + "schemaVersion": 22, "style": "dark", "tags": [], "templating": { "list": [ { + "current": { + "text": "che", + "value": "che" + }, "hide": 0, "includeAll": false, "label": null, @@ -9726,4 +9749,4 @@ data: "title": "Che Server", "uid": "sL0Klq_mz", "version": 1 - } + } \ No newline at end of file diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/MultiuserJpaWorkspaceDao.java b/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/MultiuserJpaWorkspaceDao.java index 59280e0580a..a97c3700243 100644 --- a/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/MultiuserJpaWorkspaceDao.java +++ b/multiuser/permission/che-multiuser-permission-workspace/src/main/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/MultiuserJpaWorkspaceDao.java @@ -235,6 +235,19 @@ public Page getWorkspaces(boolean isTemporary, int maxItems, long } } + @Override + @Transactional + public long getWorkspacesTotalCount() throws ServerException { + try { + return managerProvider + .get() + .createNamedQuery("Workspace.getWorkspacesTotalCount", Long.class) + .getSingleResult(); + } catch (RuntimeException x) { + throw new ServerException(x.getLocalizedMessage(), x); + } + } + @Transactional protected void doCreate(WorkspaceImpl workspace) { if (workspace.getConfig() != null) { diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/jpa/MultiuserJpaWorkspaceDaoTest.java b/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/jpa/MultiuserJpaWorkspaceDaoTest.java index 66ef6893d5b..3d993b036fb 100644 --- a/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/jpa/MultiuserJpaWorkspaceDaoTest.java +++ b/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/jpa/MultiuserJpaWorkspaceDaoTest.java @@ -20,6 +20,7 @@ import java.util.List; import javax.persistence.EntityManager; import org.eclipse.che.account.spi.AccountImpl; +import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.user.server.model.impl.UserImpl; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; @@ -126,6 +127,11 @@ public void cleanup() { manager.getTransaction().commit(); } + @Test + public void shouldGetTotalWorkspaceCount() throws ServerException { + assertEquals(dao.getWorkspacesTotalCount(), 3); + } + @AfterClass public void shutdown() throws Exception { tckResourcesCleaner.clean(); diff --git a/wsmaster/che-core-api-metrics/pom.xml b/wsmaster/che-core-api-metrics/pom.xml index ab259dc493c..e8e02a8678d 100644 --- a/wsmaster/che-core-api-metrics/pom.xml +++ b/wsmaster/che-core-api-metrics/pom.xml @@ -51,6 +51,10 @@ org.eclipse.che.core che-core-api-user + + org.eclipse.che.core + che-core-api-workspace + org.eclipse.che.core che-core-api-workspace-activity diff --git a/wsmaster/che-core-api-metrics/src/main/java/org/eclipse/che/api/metrics/WorkspaceMeterBinder.java b/wsmaster/che-core-api-metrics/src/main/java/org/eclipse/che/api/metrics/WorkspaceMeterBinder.java new file mode 100644 index 00000000000..41da43ef339 --- /dev/null +++ b/wsmaster/che-core-api-metrics/src/main/java/org/eclipse/che/api/metrics/WorkspaceMeterBinder.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2012-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.metrics; + +import static org.eclipse.che.api.metrics.WorkspaceBinders.workspaceMetric; + +import io.micrometer.core.instrument.Gauge; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.binder.MeterBinder; +import javax.inject.Inject; +import javax.inject.Singleton; +import org.eclipse.che.api.core.ServerException; +import org.eclipse.che.api.workspace.server.WorkspaceManager; + +/** Provides metrics of workspace. */ +@Singleton +public class WorkspaceMeterBinder implements MeterBinder { + private final WorkspaceManager workspaceManager; + + @Inject + public WorkspaceMeterBinder(WorkspaceManager workspaceManager) { + this.workspaceManager = workspaceManager; + } + + @Override + public void bindTo(MeterRegistry registry) { + Gauge.builder(workspaceMetric("total"), this::count) + .description("Total number of workspaces") + .register(registry); + } + + private double count() { + try { + return workspaceManager.getWorkspacesTotalCount(); + } catch (ServerException e) { + return Double.NaN; + } + } +} diff --git a/wsmaster/che-core-api-metrics/src/main/java/org/eclipse/che/api/metrics/WsMasterMetricsModule.java b/wsmaster/che-core-api-metrics/src/main/java/org/eclipse/che/api/metrics/WsMasterMetricsModule.java index ce4475f109d..1e0e212f4ff 100644 --- a/wsmaster/che-core-api-metrics/src/main/java/org/eclipse/che/api/metrics/WsMasterMetricsModule.java +++ b/wsmaster/che-core-api-metrics/src/main/java/org/eclipse/che/api/metrics/WsMasterMetricsModule.java @@ -35,5 +35,6 @@ protected void configure() { meterMultibinder.addBinding().to(WorkspaceStartAttemptsMeterBinder.class); meterMultibinder.addBinding().to(UserMeterBinder.class); meterMultibinder.addBinding().to(RuntimeLogMeterBinder.class); + meterMultibinder.addBinding().to(WorkspaceMeterBinder.class); } } diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java index fd964c4c486..af0e5dff505 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java @@ -585,6 +585,16 @@ private void handleStartupSuccess(String workspaceId) { } } + /** + * Gets total count of all workspaces + * + * @return workspaces count + * @throws ServerException when any error occurs + */ + public long getWorkspacesTotalCount() throws ServerException { + return workspaceDao.getWorkspacesTotalCount(); + } + private WorkspaceImpl doCreateWorkspace( WorkspaceConfig config, Account account, Map attributes, boolean isTemporary) throws ConflictException, ServerException { diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java index 0df54a1d7cb..17b1df9734b 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/jpa/JpaWorkspaceDao.java @@ -262,6 +262,19 @@ protected WorkspaceImpl doUpdate(WorkspaceImpl update) throws NotFoundException return merged; } + @Override + @Transactional + public long getWorkspacesTotalCount() throws ServerException { + try { + return managerProvider + .get() + .createNamedQuery("Workspace.getWorkspacesTotalCount", Long.class) + .getSingleResult(); + } catch (RuntimeException x) { + throw new ServerException(x.getLocalizedMessage(), x); + } + } + @Singleton public static class RemoveWorkspaceBeforeAccountRemovedEventSubscriber extends CascadeEventSubscriber { diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java index 00c7ed97b68..b315693c976 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceImpl.java @@ -67,6 +67,9 @@ @NamedQuery( name = "Workspace.getByNamespaceCount", query = "SELECT COUNT(w) " + "FROM Workspace w " + "WHERE w.account.name = :namespace "), + @NamedQuery( + name = "Workspace.getWorkspacesTotalCount", + query = "SELECT COUNT(w) FROM Workspace w"), @NamedQuery( name = "Workspace.getByTemporaryCount", query = "SELECT COUNT(w) " + "FROM Workspace w " + "WHERE w.isTemporary = :temporary ") diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/WorkspaceDao.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/WorkspaceDao.java index 6c5f8b03063..7df8ebaef74 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/WorkspaceDao.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/spi/WorkspaceDao.java @@ -134,4 +134,12 @@ Page getWorkspaces(String userId, int maxItems, long skipCount) */ Page getWorkspaces(boolean isTemporary, int maxItems, long skipCount) throws ServerException; + + /** + * Get the count of all workspaces from the persistent layer. + * + * @return workspace count + * @throws ServerException when any error occurs + */ + long getWorkspacesTotalCount() throws ServerException; } diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java index d358001b10e..8d915f2700f 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java @@ -127,6 +127,31 @@ public void createEntities() throws TckRepositoryException { workspaceRepo.createAll(Stream.of(workspaces).map(WorkspaceImpl::new).collect(toList())); } + @Test + public void shouldBeAbleToCountWorkspaces() throws ServerException { + assertEquals(workspaceDao.getWorkspacesTotalCount(), COUNT_OF_WORKSPACES); + } + + @Test + public void shouldBeAbleToCountNewWorkspaces() throws ServerException, TckRepositoryException { + // given + // when + workspaceRepo.createAll( + ImmutableList.of(createWorkspaceFromDevfile("id222", accounts[0], "name-bbb"))); + // then + assertEquals(workspaceDao.getWorkspacesTotalCount(), COUNT_OF_WORKSPACES + 1); + } + + @Test + public void shouldBeAbleToSubtractRemovedWorkspaces() + throws ServerException, TckRepositoryException { + // given + // when + workspaceDao.remove(workspaces[1].getId()); + // then + assertEquals(workspaceDao.getWorkspacesTotalCount(), COUNT_OF_WORKSPACES - 1); + } + @Test public void shouldGetWorkspaceById() throws Exception { final WorkspaceImpl workspace = workspaces[0];