diff --git a/debian/cloudstack-usage.postinst b/debian/cloudstack-usage.postinst index f39725687cb..61a6b14ce32 100755 --- a/debian/cloudstack-usage.postinst +++ b/debian/cloudstack-usage.postinst @@ -41,6 +41,13 @@ case "$1" in ln -s /etc/cloudstack/management/key /etc/cloudstack/usage/key fi + # creating the last sanity checked id pointer + mkdir -p /usr/local/libexec + if [ ! -f "/usr/local/libexec/sanity-check-last-id" ]; then + echo 1 > /usr/local/libexec/sanity-check-last-id + fi + chown cloud:cloud /usr/local/libexec/sanity-check-last-id + # Print help message if [ -f "/usr/share/cloudstack-common/scripts/installer/cloudstack-help-text" ];then acs_version=$(dpkg -l |grep cloudstack-usage |head -n1 |awk '{print $3}') diff --git a/packaging/centos7/cloud.spec b/packaging/centos7/cloud.spec index aabc46ad6b5..1cbd4235b58 100644 --- a/packaging/centos7/cloud.spec +++ b/packaging/centos7/cloud.spec @@ -552,6 +552,12 @@ if [ ! -f "%{_sysconfdir}/%{name}/usage/key" ]; then ln -s %{_sysconfdir}/%{name}/management/key %{_sysconfdir}/%{name}/usage/key fi +mkdir -p /usr/local/libexec +if [ ! -f "/usr/local/libexec/sanity-check-last-id" ]; then + echo 1 > /usr/local/libexec/sanity-check-last-id +fi +chown cloud:cloud /usr/local/libexec/sanity-check-last-id + %posttrans usage # Print help message if [ -f "/usr/share/cloudstack-common/scripts/installer/cloudstack-help-text" ];then @@ -689,6 +695,9 @@ pip3 install --upgrade urllib3 %attr(0755,root,root) %{_bindir}/cloudstack-setup-baremetal %changelog +* Fri Oct 14 2022 Daan Hoogland 4.18.0 +- initialising sanity check pointer file + * Thu Apr 30 2015 Rohit Yadav 4.6.0 - Remove awsapi package diff --git a/packaging/centos8/cloud.spec b/packaging/centos8/cloud.spec index af3b9200990..57d4e68d8ea 100644 --- a/packaging/centos8/cloud.spec +++ b/packaging/centos8/cloud.spec @@ -543,6 +543,12 @@ if [ ! -f "%{_sysconfdir}/%{name}/usage/key" ]; then ln -s %{_sysconfdir}/%{name}/management/key %{_sysconfdir}/%{name}/usage/key fi +mkdir -p /usr/local/libexec +if [ ! -f "/usr/local/libexec/sanity-check-last-id" ]; then + echo 1 > /usr/local/libexec/sanity-check-last-id +fi +chown cloud:cloud /usr/local/libexec/sanity-check-last-id + %posttrans usage # Print help message if [ -f "/usr/share/cloudstack-common/scripts/installer/cloudstack-help-text" ];then @@ -677,6 +683,9 @@ pip install --upgrade /usr/share/cloudstack-marvin/Marvin-*.tar.gz %attr(0755,root,root) %{_bindir}/cloudstack-setup-baremetal %changelog +* Fri Oct 14 2022 Daan Hoogland 4.18.0 +- initialising sanity check pointer file + * Thu Apr 30 2015 Rohit Yadav 4.6.0 - Remove awsapi package diff --git a/packaging/suse15/cloud.spec b/packaging/suse15/cloud.spec index 334ba6ff81d..48697879b06 100644 --- a/packaging/suse15/cloud.spec +++ b/packaging/suse15/cloud.spec @@ -537,6 +537,12 @@ if [ ! -f "%{_sysconfdir}/%{name}/usage/key" ]; then ln -s %{_sysconfdir}/%{name}/management/key %{_sysconfdir}/%{name}/usage/key fi +mkdir -p /usr/local/libexec +if [ ! -f "/usr/local/libexec/sanity-check-last-id" ]; then + echo 1 > /usr/local/libexec/sanity-check-last-id +fi +chown cloud:cloud /usr/local/libexec/sanity-check-last-id + %posttrans usage # Print help message if [ -f "/usr/share/cloudstack-common/scripts/installer/cloudstack-help-text" ];then @@ -671,6 +677,9 @@ pip install --upgrade /usr/share/cloudstack-marvin/Marvin-*.tar.gz %attr(0755,root,root) %{_bindir}/cloudstack-setup-baremetal %changelog +* Fri Oct 14 2022 Daan Hoogland 4.18.0 +- initialising sanity check pointer file + * Tue Jun 29 2021 David Jumani 4.16.0 - Adding SUSE 15 support diff --git a/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java b/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java index cb9b572373b..9cf1e30865c 100644 --- a/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java +++ b/usage/src/main/java/com/cloud/usage/UsageManagerImpl.java @@ -2156,6 +2156,7 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna private class SanityCheck extends ManagedContextRunnable { @Override protected void runInContext() { + s_logger.info("running sanity check"); UsageSanityChecker usc = new UsageSanityChecker(); try { String errors = usc.runSanityCheck(); diff --git a/usage/src/main/java/com/cloud/usage/UsageSanityChecker.java b/usage/src/main/java/com/cloud/usage/UsageSanityChecker.java index 7a790a502e4..35dd31e9434 100644 --- a/usage/src/main/java/com/cloud/usage/UsageSanityChecker.java +++ b/usage/src/main/java/com/cloud/usage/UsageSanityChecker.java @@ -51,7 +51,7 @@ public class UsageSanityChecker { protected void reset() { errors = new StringBuilder(); - checkCases = new ArrayList(); + checkCases = new ArrayList<>(); } protected boolean checkItemCountByPstmt() throws SQLException { @@ -69,48 +69,51 @@ public class UsageSanityChecker { /* * Check for item usage records which are created after it is removed */ - try (PreparedStatement pstmt = conn.prepareStatement(checkCase.sqlTemplate)) { - if(checkCase.checkId) { - pstmt.setInt(1, lastId); - pstmt.setInt(2, maxId); - } - try(ResultSet rs = pstmt.executeQuery();) { - if (rs.next() && (rs.getInt(1) > 0)) { - errors.append(String.format("Error: Found %s %s\n", rs.getInt(1), checkCase.itemName)); - checkOk = false; + try (PreparedStatement pstmt = conn.prepareStatement(checkCase.getSqlTemplate())) { + if (checkCase.isCheckId()) { + if (lastId > 0) { + pstmt.setInt(1, lastId); + } + if (maxId > lastId) { + pstmt.setInt(2, maxId); } - }catch (Exception e) - { - s_logger.error("checkItemCountByPstmt:Exception:"+e.getMessage()); - throw new CloudRuntimeException("checkItemCountByPstmt:Exception:"+e.getMessage(),e); } + checkOk = isCheckOkForPstmt(checkCase, checkOk, pstmt); } catch (Exception e) { - s_logger.error("checkItemCountByPstmt:Exception:"+e.getMessage()); - throw new CloudRuntimeException("checkItemCountByPstmt:Exception:"+e.getMessage(),e); + throwPreparedStatementExcecutionException("preparing statement", checkCase.getSqlTemplate(), e); } return checkOk; } + private boolean isCheckOkForPstmt(CheckCase checkCase, boolean checkOk, PreparedStatement pstmt) { + try (ResultSet rs = pstmt.executeQuery();) { + if (rs.next() && (rs.getInt(1) > 0)) { + errors.append(String.format("Error: Found %s %s%n", rs.getInt(1), checkCase.getItemName())); + checkOk = false; + } + } catch (Exception e) + { + throwPreparedStatementExcecutionException("check is failing", pstmt.toString(), e); + } + return checkOk; + } + + private static void throwPreparedStatementExcecutionException(String msgPrefix, String stmt, Exception e) { + String msg = String.format("%s for prepared statement \"%s\" reason: %s", msgPrefix, stmt, e.getMessage()); + s_logger.error(msg); + throw new CloudRuntimeException(msg, e); + } + protected void checkMaxUsage() throws SQLException { int aggregationRange = DEFAULT_AGGREGATION_RANGE; - try (PreparedStatement pstmt = conn.prepareStatement( - "SELECT value FROM `cloud`.`configuration` where name = 'usage.stats.job.aggregation.range'");) + String sql = "SELECT value FROM `cloud`.`configuration` WHERE name = 'usage.stats.job.aggregation.range'"; + try (PreparedStatement pstmt = conn.prepareStatement(sql);) { - try(ResultSet rs = pstmt.executeQuery();) { - if (rs.next()) { - aggregationRange = rs.getInt(1); - } else { - s_logger.debug("Failed to retrieve aggregation range. Using default : " + aggregationRange); - } - }catch (SQLException e) { - s_logger.error("checkMaxUsage:Exception:"+e.getMessage()); - throw new CloudRuntimeException("checkMaxUsage:Exception:"+e.getMessage()); - } + aggregationRange = getAggregationRange(aggregationRange, pstmt); } catch (SQLException e) { - s_logger.error("checkMaxUsage:Exception:"+e.getMessage()); - throw new CloudRuntimeException("checkMaxUsage:Exception:"+e.getMessage()); + throwPreparedStatementExcecutionException("preparing atatement", sql, e); } int aggregationHours = aggregationRange / 60; @@ -120,6 +123,21 @@ public class UsageSanityChecker { lastCheckId); } + private static int getAggregationRange(int aggregationRange, PreparedStatement pstmt) { + try (ResultSet rs = pstmt.executeQuery();) { + if (rs.next()) { + aggregationRange = rs.getInt(1); + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Failed to retrieve aggregation range. Using default : " + aggregationRange); + } + } + } catch (SQLException e) { + throwPreparedStatementExcecutionException("retrieval aggregate value is failing", pstmt.toString(), e); + } + return aggregationRange; + } + protected void checkVmUsage() { addCheckCase("select count(*) from cloud_usage.cloud_usage cu inner join cloud.vm_instance vm " + "where vm.type = 'User' and cu.usage_type in (1 , 2) " @@ -170,14 +188,21 @@ public class UsageSanityChecker { } protected void readLastCheckId(){ + if (s_logger.isDebugEnabled()) { + s_logger.debug("reading last checked id for sanity check"); + } try(BufferedReader reader = new BufferedReader(new FileReader(lastCheckFile));) { String lastIdText = null; lastId = -1; - if ((reader != null) && (lastIdText = reader.readLine()) != null) { + if ((lastIdText = reader.readLine()) != null) { lastId = Integer.parseInt(lastIdText); } } catch (Exception e) { - s_logger.error("readLastCheckId:Exception:"+e.getMessage(),e); + String msg = String.format("error reading the LastCheckId reason: %s", e.getMessage()); + s_logger.error(msg); + s_logger.debug(msg, e); + } finally { + s_logger.info(String.format("using %d as last checked id to start from in sanity check", lastId)); } } @@ -188,7 +213,9 @@ public class UsageSanityChecker { maxId = -1; if (rs.next() && (rs.getInt(1) > 0)) { maxId = rs.getInt(1); - lastCheckId += " and cu.id <= ?"; + if (maxId > lastId) { + lastCheckId += " and cu.id <= ?"; + } } }catch (Exception e) { s_logger.error("readMaxId:"+e.getMessage(),e); @@ -196,12 +223,13 @@ public class UsageSanityChecker { } protected void updateNewMaxId() { + s_logger.info(String.format("writing %d as the new last id checked", maxId)); try (FileWriter fstream = new FileWriter(lastCheckFile); - BufferedWriter out = new BufferedWriter(fstream); + BufferedWriter out = new BufferedWriter(fstream); ){ out.write("" + maxId); } catch (IOException e) { - s_logger.error("updateNewMaxId:Exception:"+e.getMessage()); + s_logger.error(String.format("Exception writing the last checked id: %d reason: %s", maxId, e.getMessage())); // Error while writing last check id } } @@ -238,13 +266,17 @@ public class UsageSanityChecker { return TransactionLegacy.getStandaloneConnection(); } - public static void main(String args[]) { + /** + * usage something like: /usr/bin/java -Xmx2G -cp /usr/share/cloudstack-usage/*:/usr/share/cloudstack-usage/lib/*:/usr/share/cloudstack-mysql-ha/lib/*:/etc/cloudstack/usage:/usr/share/java/mysql-connector-java.jar:/usr/share/cloudstack-common com.cloud.usage.UsageSanityChecker + * @param args none + */ + public static void main(String[] args) { UsageSanityChecker usc = new UsageSanityChecker(); String sanityErrors; try { sanityErrors = usc.runSanityCheck(); if (sanityErrors.length() > 0) { - s_logger.error(sanityErrors.toString()); + s_logger.error(sanityErrors); } } catch (SQLException e) { e.printStackTrace(); @@ -266,19 +298,43 @@ public class UsageSanityChecker { * encapsulating what change for each specific case */ class CheckCase { - public String sqlTemplate; - public String itemName; - public boolean checkId = false; + public String getSqlTemplate() { + return this.sqlTemplate; + } + + public void setSqlTemplate(final String sqlTemplate) { + this.sqlTemplate = sqlTemplate; + } + + public String getItemName() { + return this.itemName; + } + + public void setItemName(final String itemName) { + this.itemName = itemName; + } + + public boolean isCheckId() { + return this.checkId; + } + + public void setCheckId(final boolean checkId) { + this.checkId = checkId; + } + + private String sqlTemplate; + private String itemName; + private boolean checkId = false; public CheckCase(String sqlTemplate, String itemName, String lastCheckId) { - checkId = true; - this.sqlTemplate = sqlTemplate + lastCheckId; - this.itemName = itemName; + setCheckId(true); + setSqlTemplate(sqlTemplate + lastCheckId); + setItemName(itemName); } public CheckCase(String sqlTemplate, String itemName) { checkId = false; - this.sqlTemplate = sqlTemplate; - this.itemName = itemName; + setSqlTemplate(sqlTemplate); + setItemName(itemName); } }