diff --git a/engine/schema/src/main/java/com/cloud/usage/dao/UsageJobDaoImpl.java b/engine/schema/src/main/java/com/cloud/usage/dao/UsageJobDaoImpl.java index 6f340501cf1..68ad8fa12ed 100644 --- a/engine/schema/src/main/java/com/cloud/usage/dao/UsageJobDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/usage/dao/UsageJobDaoImpl.java @@ -61,9 +61,6 @@ public class UsageJobDaoImpl extends GenericDaoBase implements public void updateJobSuccess(Long jobId, long startMillis, long endMillis, long execTime, boolean success) { TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); try { - txn.start(); - - UsageJobVO job = lockRow(jobId, Boolean.TRUE); UsageJobVO jobForUpdate = createForUpdate(); jobForUpdate.setStartMillis(startMillis); jobForUpdate.setEndMillis(endMillis); @@ -71,11 +68,8 @@ public class UsageJobDaoImpl extends GenericDaoBase implements jobForUpdate.setStartDate(new Date(startMillis)); jobForUpdate.setEndDate(new Date(endMillis)); jobForUpdate.setSuccess(success); - update(job.getId(), jobForUpdate); - - txn.commit(); + update(jobId, jobForUpdate); } catch (Exception ex) { - txn.rollback(); logger.error("error updating job success date", ex); throw new CloudRuntimeException(ex.getMessage()); } finally { diff --git a/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/CloudStackExtendedLifeCycle.java b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/CloudStackExtendedLifeCycle.java index 170e3b40e94..bd3e424f767 100644 --- a/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/CloudStackExtendedLifeCycle.java +++ b/framework/spring/lifecycle/src/main/java/org/apache/cloudstack/spring/lifecycle/CloudStackExtendedLifeCycle.java @@ -73,7 +73,8 @@ public class CloudStackExtendedLifeCycle extends AbstractBeanCollector { try { lifecycle.start(); } catch (Exception e) { - logger.error("Error on starting bean {} - {}", lifecycle.getName(), e.getMessage(), e); + logger.error("Error on starting bean [{}] due to: {}", lifecycle.getName(), e); + throw new CloudRuntimeException("Failed to start bean [" + lifecycle.getName() + "]"); } if (lifecycle instanceof ManagementBean) { diff --git a/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/model/impl/DefaultModuleDefinitionSet.java b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/model/impl/DefaultModuleDefinitionSet.java index 2a6d0b63e5c..78693f72140 100644 --- a/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/model/impl/DefaultModuleDefinitionSet.java +++ b/framework/spring/module/src/main/java/org/apache/cloudstack/spring/module/model/impl/DefaultModuleDefinitionSet.java @@ -112,10 +112,8 @@ public class DefaultModuleDefinitionSet implements ModuleDefinitionSet { logger.debug(String.format("Could not get module [%s] context bean.", moduleDefinitionName)); } } catch (BeansException e) { - logger.warn(String.format("Failed to start module [%s] due to: [%s].", moduleDefinitionName, e.getMessage())); - if (logger.isDebugEnabled()) { - logger.debug(String.format("module start failure of module [%s] was due to: ", moduleDefinitionName), e); - } + logger.error("Failed to start module [{}] due to: {}", def.getName(), e); + throw new RuntimeException(String.format("Failed to start module [%s]", def.getName())); } } catch (EmptyStackException e) { logger.warn(String.format("Failed to obtain module context due to [%s]. Using root context instead.", e.getMessage())); @@ -147,10 +145,8 @@ public class DefaultModuleDefinitionSet implements ModuleDefinitionSet { logger.debug("Failed to obtain module context: ", e); } } catch (BeansException e) { - logger.warn(String.format("Failed to start module [%s] due to: [%s].", def.getName(), e.getMessage())); - if (logger.isDebugEnabled()) { - logger.debug(String.format("module start failure of module [%s] was due to: ", def.getName()), e); - } + logger.error("Failed to load module [{}] due to: {}", def.getName(), e); + throw new RuntimeException(String.format("Failed to load module [%s]", def.getName())); } } }); diff --git a/pom.xml b/pom.xml index 38a559ba831..cc14a86fb8b 100644 --- a/pom.xml +++ b/pom.xml @@ -196,6 +196,8 @@ 3.1.7 3.25.5 8.6.0 + 1.51.0 + 2.16.0 @@ -434,6 +436,16 @@ commons-validator ${cs.commons-validator.version} + + io.opentelemetry + opentelemetry-api + ${cs.opentelemetry.version} + + + io.opentelemetry.instrumentation + opentelemetry-instrumentation-annotations + ${cs.opentelemetry-instrumentation.version} + javax.annotation javax.annotation-api diff --git a/server/pom.xml b/server/pom.xml index 2b35a0f42ac..2698f1264ac 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -197,6 +197,14 @@ 4.23.0.0-SNAPSHOT compile + + io.opentelemetry.instrumentation + opentelemetry-instrumentation-annotations + + + io.opentelemetry + opentelemetry-api + diff --git a/server/src/main/java/com/cloud/api/ApiServer.java b/server/src/main/java/com/cloud/api/ApiServer.java index 1bda053ec19..1aaf593a8da 100644 --- a/server/src/main/java/com/cloud/api/ApiServer.java +++ b/server/src/main/java/com/cloud/api/ApiServer.java @@ -62,6 +62,9 @@ import javax.naming.ConfigurationException; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.instrumentation.annotations.WithSpan; + import org.apache.cloudstack.acl.APIChecker; import org.apache.cloudstack.acl.ApiKeyPairManagerImpl; import org.apache.cloudstack.acl.apikeypair.ApiKeyPair; @@ -627,6 +630,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer } @Override + @WithSpan("ApiServer.handleRequest") @SuppressWarnings("rawtypes") public String handleRequest(final Map params, final String responseType, final StringBuilder auditTrailSb) throws ServerApiException { checkCharacterInkParams(params); @@ -636,6 +640,10 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer try { command = (String[])params.get("command"); + if (command != null && command.length > 0) { + Span.current().updateName("ApiServer.handleRequest " + command[0]); + Span.current().setAttribute("api.command", command[0]); + } if (command == null) { logger.error("invalid request, no command sent"); if (logger.isTraceEnabled()) { diff --git a/server/src/main/java/com/cloud/server/StatsCollector.java b/server/src/main/java/com/cloud/server/StatsCollector.java index 049ed454361..293b28c6cb4 100644 --- a/server/src/main/java/com/cloud/server/StatsCollector.java +++ b/server/src/main/java/com/cloud/server/StatsCollector.java @@ -166,6 +166,7 @@ import com.codahale.metrics.JvmAttributeGaugeSet; import com.codahale.metrics.Metric; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.MetricSet; +import com.codahale.metrics.JmxReporter; import com.codahale.metrics.jvm.BufferPoolMetricSet; import com.codahale.metrics.jvm.GarbageCollectorMetricSet; import com.codahale.metrics.jvm.MemoryUsageGaugeSet; @@ -387,7 +388,11 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc private boolean _dailyOrHourly = false; protected long managementServerNodeId = ManagementServerNode.getManagementServerId(); protected long msId = managementServerNodeId; - final static MetricRegistry METRIC_REGISTRY = new MetricRegistry(); + public static final MetricRegistry METRIC_REGISTRY = new MetricRegistry(); + + public static void registerMetric(String name, Metric metric) { + METRIC_REGISTRY.register(name, metric); + } public static StatsCollector getInstance() { return s_instance; @@ -410,6 +415,11 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc registerAll("memory", new MemoryUsageGaugeSet(), METRIC_REGISTRY); registerAll("threads", new ThreadStatesGaugeSet(), METRIC_REGISTRY); registerAll("jvm", new JvmAttributeGaugeSet(), METRIC_REGISTRY); + try { + JmxReporter.forRegistry(METRIC_REGISTRY).inDomain("vm-extra").build().start(); + } catch (Exception e) { + logger.warn("Failed to start JMX reporter for METRIC_REGISTRY, metrics will not be visible via JMX", e); + } return true; } @Override diff --git a/tools/docker/supervisord.conf b/tools/docker/supervisord.conf index 93f01387575..1c14578c4cf 100644 --- a/tools/docker/supervisord.conf +++ b/tools/docker/supervisord.conf @@ -12,6 +12,7 @@ command=/bin/bash -c "mvn -pl client jetty:run -Dsimulator -Dorg.eclipse.jetty.a directory=/root stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 +redirect_stderr=true user=root [program:cloudstack-ui] diff --git a/ui/src/components/view/ImageDeployInstanceButton.vue b/ui/src/components/view/ImageDeployInstanceButton.vue index 2cdd5a0af46..a4d47d4464a 100644 --- a/ui/src/components/view/ImageDeployInstanceButton.vue +++ b/ui/src/components/view/ImageDeployInstanceButton.vue @@ -83,7 +83,8 @@ export default { computed: { allowed () { return (this.$route.meta.name === 'template' || - (this.$route.meta.name === 'iso' && this.resource.bootable)) + (this.$route.meta.name === 'iso' && this.resource?.bootable)) && + !!this.resource?.isready } }, methods: { @@ -91,7 +92,7 @@ export default { this.fetchResourceData() }, fetchResourceData () { - if (!this.resource || !this.resource.id) { + if (!this.resource || !this.resource.id || !this.resource.isready) { return } const params = { diff --git a/ui/src/views/compute/wizard/VnfNicsSelection.vue b/ui/src/views/compute/wizard/VnfNicsSelection.vue index 40bdc1c676a..538c9553eb4 100644 --- a/ui/src/views/compute/wizard/VnfNicsSelection.vue +++ b/ui/src/views/compute/wizard/VnfNicsSelection.vue @@ -50,7 +50,7 @@