This is an automated email from the ASF dual-hosted git repository.

dahn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/main by this push:
     new 1065e9046b1 Fix backup dates (#6473)
1065e9046b1 is described below

commit 1065e9046b15360713a36c364fc25fc77fe362d4
Author: João Jandre <[email protected]>
AuthorDate: Fri Aug 18 05:51:36 2023 -0300

    Fix backup dates (#6473)
    
    Co-authored-by: João Paraquetti <[email protected]>
    Co-authored-by: dahn <[email protected]>
---
 .../cloudstack/api/response/BackupResponse.java    |  10 +-
 .../api/response/BackupRestorePointResponse.java   |  10 +-
 .../java/org/apache/cloudstack/backup/Backup.java  |  14 +--
 .../com/cloud/upgrade/dao/Upgrade41810to41900.java | 111 +++++++++++++++++++++
 .../org/apache/cloudstack/backup/BackupVO.java     |  12 ++-
 .../cloudstack/backup/DummyBackupProvider.java     |   2 +-
 .../cloudstack/backup/NetworkerBackupProvider.java |  11 +-
 .../backup/networker/NetworkerClient.java          |  10 +-
 .../cloudstack/backup/veeam/VeeamClient.java       |  10 +-
 ui/src/components/view/ListResourceTable.vue       |   5 +
 10 files changed, 171 insertions(+), 24 deletions(-)

diff --git 
a/api/src/main/java/org/apache/cloudstack/api/response/BackupResponse.java 
b/api/src/main/java/org/apache/cloudstack/api/response/BackupResponse.java
index d0c8e588450..63419680fea 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/BackupResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/BackupResponse.java
@@ -25,6 +25,8 @@ import org.apache.cloudstack.backup.Backup;
 import com.cloud.serializer.Param;
 import com.google.gson.annotations.SerializedName;
 
+import java.util.Date;
+
 @EntityReference(value = Backup.class)
 public class BackupResponse extends BaseResponse {
 
@@ -50,7 +52,7 @@ public class BackupResponse extends BaseResponse {
 
     @SerializedName(ApiConstants.CREATED)
     @Param(description = "backup date")
-    private String date;
+    private Date date;
 
     @SerializedName(ApiConstants.SIZE)
     @Param(description = "backup size in bytes")
@@ -140,11 +142,11 @@ public class BackupResponse extends BaseResponse {
         this.type = type;
     }
 
-    public String getDate() {
-        return date;
+    public Date getDate() {
+        return this.date;
     }
 
-    public void setDate(String date) {
+    public void setDate(Date date) {
         this.date = date;
     }
 
diff --git 
a/api/src/main/java/org/apache/cloudstack/api/response/BackupRestorePointResponse.java
 
b/api/src/main/java/org/apache/cloudstack/api/response/BackupRestorePointResponse.java
index afb3e9ffc5f..22bb099b1b0 100644
--- 
a/api/src/main/java/org/apache/cloudstack/api/response/BackupRestorePointResponse.java
+++ 
b/api/src/main/java/org/apache/cloudstack/api/response/BackupRestorePointResponse.java
@@ -25,6 +25,8 @@ import org.apache.cloudstack.backup.Backup;
 import com.cloud.serializer.Param;
 import com.google.gson.annotations.SerializedName;
 
+import java.util.Date;
+
 @EntityReference(value = Backup.RestorePoint.class)
 public class BackupRestorePointResponse extends BaseResponse {
 
@@ -34,7 +36,7 @@ public class BackupRestorePointResponse extends BaseResponse {
 
     @SerializedName(ApiConstants.CREATED)
     @Param(description = "created time")
-    private String created;
+    private Date created;
 
     @SerializedName(ApiConstants.TYPE)
     @Param(description = "restore point type")
@@ -48,11 +50,11 @@ public class BackupRestorePointResponse extends 
BaseResponse {
         this.id = id;
     }
 
-    public String getCreated() {
-        return created;
+    public Date getCreated() {
+        return this.created;
     }
 
-    public void setCreated(String created) {
+    public void setCreated(Date created) {
         this.created = created;
     }
 
diff --git a/api/src/main/java/org/apache/cloudstack/backup/Backup.java 
b/api/src/main/java/org/apache/cloudstack/backup/Backup.java
index 75c7ab4cca5..f369367957d 100644
--- a/api/src/main/java/org/apache/cloudstack/backup/Backup.java
+++ b/api/src/main/java/org/apache/cloudstack/backup/Backup.java
@@ -17,6 +17,8 @@
 
 package org.apache.cloudstack.backup;
 
+import java.util.Date;
+
 import org.apache.cloudstack.acl.ControlledEntity;
 import org.apache.cloudstack.api.Identity;
 import org.apache.cloudstack.api.InternalIdentity;
@@ -58,10 +60,10 @@ public interface Backup extends ControlledEntity, 
InternalIdentity, Identity {
 
     class RestorePoint {
         private String id;
-        private String created;
+        private Date created;
         private String type;
 
-        public RestorePoint(String id, String created, String type) {
+        public RestorePoint(String id, Date created, String type) {
             this.id = id;
             this.created = created;
             this.type = type;
@@ -75,11 +77,11 @@ public interface Backup extends ControlledEntity, 
InternalIdentity, Identity {
             this.id = id;
         }
 
-        public String getCreated() {
-            return created;
+        public Date getCreated() {
+            return this.created;
         }
 
-        public void setCreated(String created) {
+        public void setCreated(Date created) {
             this.created = created;
         }
 
@@ -134,7 +136,7 @@ public interface Backup extends ControlledEntity, 
InternalIdentity, Identity {
     long getVmId();
     String getExternalId();
     String getType();
-    String getDate();
+    Date getDate();
     Backup.Status getStatus();
     Long getSize();
     Long getProtectedSize();
diff --git 
a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41810to41900.java 
b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41810to41900.java
index c9ac468dc53..57f87d1f2cc 100644
--- a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41810to41900.java
+++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41810to41900.java
@@ -17,16 +17,27 @@
 package com.cloud.upgrade.dao;
 
 import com.cloud.upgrade.SystemVmTemplateRegistration;
+import com.cloud.utils.DateUtil;
 import com.cloud.utils.exception.CloudRuntimeException;
 import org.apache.log4j.Logger;
 
 import java.io.InputStream;
 import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 
 public class Upgrade41810to41900 implements DbUpgrade, 
DbUpgradeSystemVmTemplate {
     final static Logger LOG = Logger.getLogger(Upgrade41810to41900.class);
     private SystemVmTemplateRegistration systemVmTemplateRegistration;
 
+    private final SimpleDateFormat[] formats = {
+            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"), new 
SimpleDateFormat("MM/dd/yyyy HH:mm:ss"), new SimpleDateFormat("dd/MM/yyyy 
HH:mm:ss"),
+            new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy")};
+
     @Override
     public String[] getUpgradableVersionRange() {
         return new String[] {"4.18.1.0", "4.19.0.0"};
@@ -55,6 +66,7 @@ public class Upgrade41810to41900 implements DbUpgrade, 
DbUpgradeSystemVmTemplate
 
     @Override
     public void performDataMigration(Connection conn) {
+        migrateBackupDates(conn);
     }
 
     @Override
@@ -82,4 +94,103 @@ public class Upgrade41810to41900 implements DbUpgrade, 
DbUpgradeSystemVmTemplate
             throw new CloudRuntimeException("Failed to find / register 
SystemVM template(s)");
         }
     }
+
+    public void migrateBackupDates(Connection conn) {
+        LOG.info("Trying to convert backups' date column from varchar(255) to 
datetime type.");
+
+        modifyDateColumnNameAndCreateNewOne(conn);
+        fetchDatesAndMigrateToNewColumn(conn);
+        dropOldColumn(conn);
+
+        LOG.info("Finished converting backups' date column from varchar(255) 
to datetime.");
+    }
+
+    private void modifyDateColumnNameAndCreateNewOne(Connection conn) {
+        String alterColumnName = "ALTER TABLE `cloud`.`backups` CHANGE COLUMN 
`date` `old_date` varchar(255);";
+        try (PreparedStatement pstmt = conn.prepareStatement(alterColumnName)) 
{
+            pstmt.execute();
+        } catch (SQLException e) {
+            String message = String.format("Unable to alter backups' date 
column name due to [%s].", e.getMessage());
+            LOG.error(message, e);
+            throw new CloudRuntimeException(message, e);
+        }
+
+        String createNewColumn = "ALTER TABLE `cloud`.`backups` ADD COLUMN 
`date` DATETIME;";
+        try (PreparedStatement pstmt = conn.prepareStatement(createNewColumn)) 
{
+            pstmt.execute();
+        } catch (SQLException e) {
+            String message = String.format("Unable to crate new backups' 
column date due to [%s].", e.getMessage());
+            LOG.error(message, e);
+            throw new CloudRuntimeException(message, e);
+        }
+    }
+
+    private void fetchDatesAndMigrateToNewColumn(Connection conn) {
+        String selectBackupDates = "SELECT `id`, `old_date` FROM 
`cloud`.`backups` WHERE 1;";
+        String date;
+        java.sql.Date reformatedDate;
+
+        try (PreparedStatement pstmt = 
conn.prepareStatement(selectBackupDates)) {
+            try (ResultSet result = pstmt.executeQuery()) {
+                while (result.next()) {
+                    date = result.getString("old_date");
+                    reformatedDate = tryToTransformStringToDate(date);
+                    updateBackupDate(conn, result.getLong("id"), 
reformatedDate);
+                }
+            }
+        } catch (SQLException e) {
+            String message = String.format("Unable to retrieve backup dates 
due to [%s].", e.getMessage());
+            LOG.error(message, e);
+            throw new CloudRuntimeException(message, e);
+        }
+    }
+
+    private java.sql.Date tryToTransformStringToDate(String date) {
+        Date parsedDate = null;
+        try {
+            parsedDate = DateUtil.parseTZDateString(date);
+        } catch (ParseException e) {
+            for (SimpleDateFormat sdf: formats) {
+                try {
+                    parsedDate = sdf.parse(date);
+                } catch (ParseException ex) {
+                    continue;
+                }
+                break;
+            }
+        }
+        if (parsedDate == null) {
+            String msg = String.format("Unable to parse date [%s]. Will change 
backup date to null.", date);
+            LOG.error(msg);
+            return null;
+        }
+
+        return new java.sql.Date(parsedDate.getTime());
+    }
+
+    private void updateBackupDate(Connection conn, long id, java.sql.Date 
date) {
+        String updateBackupDate = "UPDATE `cloud`.`backups` SET `date` = ? 
WHERE `id` = ?;";
+        try (PreparedStatement pstmt = 
conn.prepareStatement(updateBackupDate)) {
+            pstmt.setDate(1, date);
+            pstmt.setLong(2, id);
+
+            pstmt.executeUpdate();
+        } catch (SQLException e) {
+            String message = String.format("Unable to update backup date with 
id [%s] to date [%s] due to [%s].", id, date, e.getMessage());
+            LOG.error(message, e);
+            throw new CloudRuntimeException(message, e);
+        }
+    }
+
+    private void dropOldColumn(Connection conn) {
+        String dropOldColumn = "ALTER TABLE `cloud`.`backups` DROP COLUMN 
`old_date`;";
+        try (PreparedStatement pstmt = conn.prepareStatement(dropOldColumn)) {
+            pstmt.execute();
+        } catch (SQLException e) {
+            String message = String.format("Unable to drop old_date column due 
to [%s].", e.getMessage());
+            LOG.error(message, e);
+            throw new CloudRuntimeException(message, e);
+        }
+    }
+
 }
diff --git 
a/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupVO.java 
b/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupVO.java
index dc47fcb6bb3..e5582609d68 100644
--- a/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupVO.java
+++ b/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupVO.java
@@ -17,6 +17,7 @@
 
 package org.apache.cloudstack.backup;
 
+import java.util.Date;
 import java.util.UUID;
 
 import javax.persistence.Column;
@@ -27,6 +28,8 @@ import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
 
 @Entity
 @Table(name = "backups")
@@ -49,7 +52,8 @@ public class BackupVO implements Backup {
     private String backupType;
 
     @Column(name = "date")
-    private String date;
+    @Temporal(value = TemporalType.DATE)
+    private Date date;
 
     @Column(name = "size")
     private Long size;
@@ -114,11 +118,11 @@ public class BackupVO implements Backup {
     }
 
     @Override
-    public String getDate() {
-        return date;
+    public Date getDate() {
+        return this.date;
     }
 
-    public void setDate(String date) {
+    public void setDate(Date date) {
         this.date = date;
     }
 
diff --git 
a/plugins/backup/dummy/src/main/java/org/apache/cloudstack/backup/DummyBackupProvider.java
 
b/plugins/backup/dummy/src/main/java/org/apache/cloudstack/backup/DummyBackupProvider.java
index 0297ce82f5e..fabc9821fd3 100644
--- 
a/plugins/backup/dummy/src/main/java/org/apache/cloudstack/backup/DummyBackupProvider.java
+++ 
b/plugins/backup/dummy/src/main/java/org/apache/cloudstack/backup/DummyBackupProvider.java
@@ -117,7 +117,7 @@ public class DummyBackupProvider extends AdapterBase 
implements BackupProvider {
         backup.setVmId(vm.getId());
         backup.setExternalId("dummy-external-id");
         backup.setType("FULL");
-        backup.setDate(new Date().toString());
+        backup.setDate(new Date());
         backup.setSize(1024L);
         backup.setProtectedSize(1024000L);
         backup.setStatus(Backup.Status.BackedUp);
diff --git 
a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/NetworkerBackupProvider.java
 
b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/NetworkerBackupProvider.java
index 37051f9b5ee..9703203108a 100644
--- 
a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/NetworkerBackupProvider.java
+++ 
b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/NetworkerBackupProvider.java
@@ -51,6 +51,8 @@ import javax.inject.Inject;
 import java.net.URISyntaxException;
 import java.security.KeyManagementException;
 import java.security.NoSuchAlgorithmException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -605,7 +607,14 @@ public class NetworkerBackupProvider extends AdapterBase 
implements BackupProvid
                         strayBackup.setVmId(vm.getId());
                         
strayBackup.setExternalId(strayNetworkerBackup.getId());
                         strayBackup.setType(strayNetworkerBackup.getType());
-                        
strayBackup.setDate(strayNetworkerBackup.getSaveTime());
+                        SimpleDateFormat formatterDateTime = new 
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
+                        try {
+                            
strayBackup.setDate(formatterDateTime.parse(strayNetworkerBackup.getSaveTime()));
+                        } catch (ParseException e) {
+                            String msg = String.format("Unable to parse date 
[%s].", strayNetworkerBackup.getSaveTime());
+                            LOG.error(msg, e);
+                            throw new CloudRuntimeException(msg, e);
+                        }
                         strayBackup.setStatus(Backup.Status.BackedUp);
                         for ( Backup.VolumeInfo thisVMVol : 
vm.getBackupVolumeList()) {
                             vmBackupSize += (thisVMVol.getSize() / 1024L 
/1024L);
diff --git 
a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/NetworkerClient.java
 
b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/NetworkerClient.java
index 939543df387..8bb89b635e9 100644
--- 
a/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/NetworkerClient.java
+++ 
b/plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/NetworkerClient.java
@@ -211,7 +211,7 @@ public class NetworkerClient {
 
         SimpleDateFormat formatterDate = new SimpleDateFormat("yyyy-MM-dd");
         SimpleDateFormat formatterTime = new SimpleDateFormat("HH:mm:ss");
-        SimpleDateFormat formatterDateTime = new 
SimpleDateFormat("yyy-MM-dd'T'HH:mm:ss");
+        SimpleDateFormat formatterDateTime = new 
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
 
         String startDate = formatterDate.format(backupJobStart);
         String startTime = formatterTime.format(backupJobStart);
@@ -252,7 +252,13 @@ public class NetworkerClient {
             backup.setVmId(vm.getId());
             backup.setExternalId(networkerLatestBackup.getId());
             backup.setType(networkerLatestBackup.getType());
-            backup.setDate(networkerLatestBackup.getCreationTime());
+            try {
+                
backup.setDate(formatterDateTime.parse(networkerLatestBackup.getCreationTime()));
+            } catch (ParseException e) {
+                String msg = String.format("Unable to parse date [%s].", 
networkerLatestBackup.getCreationTime());
+                LOG.error(msg, e);
+                throw new CloudRuntimeException(msg, e);
+            }
             backup.setSize(networkerLatestBackup.getSize().getValue());
             
backup.setProtectedSize(networkerLatestBackup.getSize().getValue());
             
backup.setStatus(org.apache.cloudstack.backup.Backup.Status.BackedUp);
diff --git 
a/plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/veeam/VeeamClient.java
 
b/plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/veeam/VeeamClient.java
index 40fbe97028a..1438dca4838 100644
--- 
a/plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/veeam/VeeamClient.java
+++ 
b/plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/veeam/VeeamClient.java
@@ -34,6 +34,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.StringJoiner;
 import java.util.UUID;
+import java.util.Date;
+import java.util.Calendar;
 
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.X509TrustManager;
@@ -660,7 +662,7 @@ public class VeeamClient {
     private Backup.RestorePoint getRestorePointFromBlock(String[] parts) {
         LOG.debug(String.format("Processing block of restore points: [%s].", 
StringUtils.join(parts, ", ")));
         String id = null;
-        String created = null;
+        Date created = null;
         String type = null;
         for (String part : parts) {
             if (part.matches("Id(\\s)+:(.)*")) {
@@ -668,7 +670,11 @@ public class VeeamClient {
                 id = split[1].trim();
             } else if (part.matches("CreationTime(\\s)+:(.)*")) {
                 String [] split = part.split(":", 2);
-                created = split[1].trim();
+                split[1] = StringUtils.trim(split[1]);
+                String [] time = split[1].split("[:/ ]");
+                Calendar cal = Calendar.getInstance();
+                cal.set(Integer.parseInt(time[2]), Integer.parseInt(time[0]) - 
1, Integer.parseInt(time[1]), Integer.parseInt(time[3]), 
Integer.parseInt(time[4]), Integer.parseInt(time[5]));
+                created = cal.getTime();
             } else if (part.matches("Type(\\s)+:(.)*")) {
                 String [] split = part.split(":");
                 type = split[1].trim();
diff --git a/ui/src/components/view/ListResourceTable.vue 
b/ui/src/components/view/ListResourceTable.vue
index c97aa0fb17e..16c1b388c5d 100644
--- a/ui/src/components/view/ListResourceTable.vue
+++ b/ui/src/components/view/ListResourceTable.vue
@@ -51,6 +51,11 @@
           <status :text="text ? text : ''" />{{ text }}
         </template>
       </template>
+
+      <template v-slot:created="{ item }">
+        {{ $toLocaleDate(item) }}
+      </template>
+
     </a-table>
 
     <div v-if="!defaultPagination" style="display: block; text-align: right; 
margin-top: 10px;">

Reply via email to