Skip to content

Commit f90bb58

Browse files
authored
Merge pull request #16 from att/FLXCLD-2859-Management-server-async-job-issue
Flxcld 2859 management server async job issue
2 parents a3b66a8 + 751466a commit f90bb58

3 files changed

Lines changed: 82 additions & 125 deletions

File tree

‎framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1153,7 +1153,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) {
11531153
final List<AsyncJobVO> jobs = _jobDao.getResetJobs(msid);
11541154
for (final AsyncJobVO job : jobs) {
11551155
if (logger.isDebugEnabled()) {
1156-
logger.debug("Cancel left-over job-" + job.getId());
1156+
logger.debug("Cancel left-over job-{} for msid {}", job.getId(), msid);
11571157
}
11581158
cleanupResources(job);
11591159
job.setStatus(JobInfo.Status.FAILED);

‎utils/src/main/java/org/apache/cloudstack/utils/identity/ManagementServerNode.java‎

Lines changed: 57 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
import java.net.InetAddress;
2323
import java.nio.charset.StandardCharsets;
2424
import java.security.MessageDigest;
25+
import java.security.NoSuchAlgorithmException;
26+
import org.apache.logging.log4j.LogManager;
27+
import org.apache.logging.log4j.Logger;
2528

2629
import com.cloud.utils.component.AdapterBase;
2730
import com.cloud.utils.component.ComponentLifecycle;
@@ -44,64 +47,70 @@
4447
*/
4548
public class ManagementServerNode extends AdapterBase implements SystemIntegrityChecker {
4649

47-
private static final String FQDN_ENV_VAR = "CLOUDSTACK_MSID_FROM_FQDN";
48-
private static final String FQDN_SYS_PROP = "cloudstack.msid.from.fqdn";
50+
private static final String FQDN_ENV_VAR = "CLOUDSTACK_MSID_FROM_ID";
51+
private static final String FQDN_SYS_PROP = "cloudstack.msid.from.id";
52+
53+
54+
// op_lock.mac is varchar(17) and holds the msid, so the id must stay within the 48-bit MAC address range.
55+
private static final int MSID_BYTES = 6;
56+
57+
private static final Logger s_logger = LogManager.getLogger(ManagementServerNode.class);
4958

5059
private static String s_nodeIdSource;
51-
private static Exception s_initError;
5260
private static final long s_nodeId = initNodeId();
5361

5462
private static long initNodeId() {
55-
if (isFqdnModeEnabled()) {
56-
return generateIdFromFqdn();
57-
}
58-
s_nodeIdSource = "mac-address";
59-
return MacAddress.getMacAddress().toLong();
60-
}
6163

62-
private static boolean isFqdnModeEnabled() {
63-
return isTruthy(System.getenv(FQDN_ENV_VAR)) || isTruthy(System.getProperty(FQDN_SYS_PROP));
64-
}
64+
s_logger.info("Initializing management server node ID");
65+
// Check if FQDN_ENV_VAR or FQDN_SYS_PROP has a value
66+
String fqdnEnv = System.getenv(FQDN_ENV_VAR);
67+
String fqdnSysProp = System.getProperty(FQDN_SYS_PROP);
6568

66-
private static boolean isTruthy(String value) {
67-
if (value == null) {
68-
return false;
69+
String identity = null;
70+
if (fqdnEnv != null) {
71+
identity = trimToNull(fqdnEnv);
72+
s_logger.info("FQDN environment variable: {}", fqdnEnv);
6973
}
70-
String trimmed = value.trim();
71-
return "true".equalsIgnoreCase(trimmed) || "1".equals(trimmed) || "yes".equalsIgnoreCase(trimmed);
74+
if (fqdnSysProp != null) {
75+
identity = trimToNull(fqdnSysProp);
76+
s_logger.info("FQDN system property: {}", fqdnSysProp);
77+
}
78+
79+
if (identity != null) {
80+
s_nodeIdSource = "fqdn";
81+
s_logger.info("Using {} for management server node ID: {}", s_nodeIdSource, identity);
82+
return hashNodeIdentity(identity);
83+
}
84+
85+
// Use mac address
86+
s_nodeIdSource = "mac-address";
87+
long macAddress = MacAddress.getMacAddress().toLong();
88+
s_logger.info("Using {} for management server node ID: {}", s_nodeIdSource, macAddress);
89+
return macAddress;
7290
}
7391

74-
/**
75-
* Derives a stable node id from a SHA-256 hash of the local FQDN.
76-
*
77-
* <p>On failure it records the cause and returns {@code 0} (an invalid id) rather than
78-
* silently reverting to an unstable MAC-based id. The invalid id makes {@link #check()}
79-
* fail the system-integrity check, which stops startup cleanly via {@link #start()}
80-
* instead of raising an {@code ExceptionInInitializerError} from static initialization.
81-
*
82-
* @return a positive, non-zero 48-bit id, or {@code 0} if it cannot be derived
83-
*/
84-
private static long generateIdFromFqdn() {
92+
static long hashNodeIdentity(String nodeIdentity) {
8593
try {
86-
String fqdn = InetAddress.getLocalHost().getCanonicalHostName();
87-
s_nodeIdSource = "fqdn:" + fqdn;
8894
MessageDigest digest = MessageDigest.getInstance("SHA-256");
89-
byte[] hash = digest.digest(fqdn.getBytes(StandardCharsets.UTF_8));
95+
byte[] hash = digest.digest(nodeIdentity.getBytes(StandardCharsets.UTF_8));
9096
long id = 0;
91-
for (int i = 0; i < 6; i++) {
92-
id = (id << 8) | (hash[i] & 0xFF);
93-
}
94-
// Ensure positive and non-zero
95-
id = id & 0x7FFFFFFFFFFFFFFFL;
96-
if (id == 0) {
97-
id = 1;
97+
for (int i = 0; i < MSID_BYTES; i++) {
98+
id = (id << 8) | (hash[i] & 0xFFL);
9899
}
99-
return id;
100-
} catch (Exception e) {
101-
s_nodeIdSource = "fqdn-error";
102-
s_initError = e;
103-
return 0;
100+
101+
return id == 0 ? 1 : id;
102+
} catch (NoSuchAlgorithmException e) {
103+
throw new CloudRuntimeException("SHA-256 algorithm not available for management server ID generation", e);
104+
}
105+
}
106+
107+
private static String trimToNull(String value) {
108+
if (value == null) {
109+
return null;
104110
}
111+
112+
String trimmed = value.trim();
113+
return trimmed.isEmpty() ? null : trimmed;
105114
}
106115

107116
public ManagementServerNode() {
@@ -111,8 +120,7 @@ public ManagementServerNode() {
111120
@Override
112121
public void check() {
113122
if (s_nodeId <= 0) {
114-
throw new CloudRuntimeException(
115-
"Unable to derive the management server node id (source: " + s_nodeIdSource + ")", s_initError);
123+
throw new CloudRuntimeException("Unable to get the management server node id");
116124
}
117125
}
118126

@@ -124,10 +132,11 @@ public static long getManagementServerId() {
124132
public boolean start() {
125133
try {
126134
check();
127-
} catch (CloudRuntimeException e) {
128-
logger.error("System integrity check failed for the management server node id", e);
129-
throw e;
135+
} catch (Exception e) {
136+
logger.error("System integrity check exception", e);
137+
System.exit(1);
130138
}
139+
131140
logger.info("Management server node id: {} (source: {})", s_nodeId, s_nodeIdSource);
132141
return true;
133142
}

‎utils/src/test/java/org/apache/cloudstack/utils/identity/ManagementServerNodeTest.java‎

Lines changed: 24 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -17,39 +17,20 @@
1717
package org.apache.cloudstack.utils.identity;
1818

1919
import static org.junit.Assert.assertEquals;
20-
import static org.junit.Assert.assertFalse;
2120
import static org.junit.Assert.assertTrue;
2221

2322
import java.lang.reflect.Method;
23+
import java.nio.charset.StandardCharsets;
24+
import java.security.MessageDigest;
2425

25-
import org.junit.After;
2626
import org.junit.Test;
2727

2828
public class ManagementServerNodeTest {
2929

30-
private static final String FQDN_SYS_PROP = "cloudstack.msid.from.fqdn";
31-
32-
@After
33-
public void tearDown() {
34-
System.clearProperty(FQDN_SYS_PROP);
35-
}
36-
37-
private static boolean invokeIsTruthy(String value) throws Exception {
38-
Method m = ManagementServerNode.class.getDeclaredMethod("isTruthy", String.class);
39-
m.setAccessible(true);
40-
return (boolean) m.invoke(null, value);
41-
}
42-
43-
private static boolean invokeIsFqdnModeEnabled() throws Exception {
44-
Method m = ManagementServerNode.class.getDeclaredMethod("isFqdnModeEnabled");
30+
private static String invokeTrimToNull(String value) throws Exception {
31+
Method m = ManagementServerNode.class.getDeclaredMethod("trimToNull", String.class);
4532
m.setAccessible(true);
46-
return (boolean) m.invoke(null);
47-
}
48-
49-
private static long invokeGenerateIdFromFqdn() throws Exception {
50-
Method m = ManagementServerNode.class.getDeclaredMethod("generateIdFromFqdn");
51-
m.setAccessible(true);
52-
return (long) m.invoke(null);
33+
return (String) m.invoke(null, value);
5334
}
5435

5536
@Test
@@ -70,68 +51,35 @@ public void testStartReturnsTrueWithValidNodeId() {
7051
}
7152

7253
@Test
73-
public void testIsTruthyRecognizesTrueValues() throws Exception {
74-
assertTrue(invokeIsTruthy("true"));
75-
assertTrue(invokeIsTruthy("TRUE"));
76-
assertTrue(invokeIsTruthy("True"));
77-
assertTrue(invokeIsTruthy("1"));
78-
assertTrue(invokeIsTruthy("yes"));
79-
assertTrue(invokeIsTruthy("YES"));
80-
}
81-
82-
@Test
83-
public void testIsTruthyTrimsWhitespace() throws Exception {
84-
assertTrue(invokeIsTruthy(" true "));
85-
assertTrue(invokeIsTruthy("\t1\n"));
86-
assertTrue(invokeIsTruthy(" yes "));
87-
}
54+
public void testHashNodeIdentityIsDeterministicAndFitsInMacAddressRange() {
55+
long first = ManagementServerNode.hashNodeIdentity("management.example.test");
56+
long second = ManagementServerNode.hashNodeIdentity("management.example.test");
8857

89-
@Test
90-
public void testIsTruthyRejectsFalseValues() throws Exception {
91-
assertFalse(invokeIsTruthy(null));
92-
assertFalse(invokeIsTruthy(""));
93-
assertFalse(invokeIsTruthy(" "));
94-
assertFalse(invokeIsTruthy("false"));
95-
assertFalse(invokeIsTruthy("0"));
96-
assertFalse(invokeIsTruthy("no"));
97-
assertFalse(invokeIsTruthy("enabled"));
98-
assertFalse(invokeIsTruthy("2"));
58+
assertEquals(first, second);
59+
assertTrue(first > 0);
60+
assertTrue(first <= 0xFFFFFFFFFFFFL);
9961
}
10062

10163
@Test
102-
public void testIsFqdnModeEnabledDefaultsFalse() throws Exception {
103-
System.clearProperty(FQDN_SYS_PROP);
104-
assertFalse(invokeIsFqdnModeEnabled());
105-
}
64+
public void testHashNodeIdentityUsesFirstSixSha256Bytes() throws Exception {
65+
String identity = "management.example.test";
66+
byte[] hash = MessageDigest.getInstance("SHA-256").digest(identity.getBytes(StandardCharsets.UTF_8));
67+
long expected = 0;
68+
for (int i = 0; i < 6; i++) {
69+
expected = (expected << 8) | (hash[i] & 0xFFL);
70+
}
10671

107-
@Test
108-
public void testIsFqdnModeEnabledWhenSystemPropertyTruthy() throws Exception {
109-
System.setProperty(FQDN_SYS_PROP, "true");
110-
assertTrue(invokeIsFqdnModeEnabled());
111-
}
112-
113-
@Test
114-
public void testIsFqdnModeEnabledWhenSystemPropertyFalsy() throws Exception {
115-
System.setProperty(FQDN_SYS_PROP, "false");
116-
assertFalse(invokeIsFqdnModeEnabled());
117-
}
118-
119-
@Test
120-
public void testGenerateIdFromFqdnIsPositiveAndNonZero() throws Exception {
121-
long id = invokeGenerateIdFromFqdn();
122-
assertTrue("Generated id must be positive and non-zero", id > 0);
72+
assertEquals(expected, ManagementServerNode.hashNodeIdentity(identity));
12373
}
12474

12575
@Test
126-
public void testGenerateIdFromFqdnFitsIn48Bits() throws Exception {
127-
long id = invokeGenerateIdFromFqdn();
128-
assertTrue("Generated id must fit within 48 bits", id <= 0xFFFFFFFFFFFFL);
76+
public void testTrimToNullReturnsTrimmedValue() throws Exception {
77+
assertEquals("management.example.test", invokeTrimToNull(" management.example.test \n"));
12978
}
13079

13180
@Test
132-
public void testGenerateIdFromFqdnIsDeterministic() throws Exception {
133-
long first = invokeGenerateIdFromFqdn();
134-
long second = invokeGenerateIdFromFqdn();
135-
assertEquals("Generated id must be stable across calls for the same FQDN", first, second);
81+
public void testTrimToNullReturnsNullForNullAndBlankValues() throws Exception {
82+
assertEquals(null, invokeTrimToNull(null));
83+
assertEquals(null, invokeTrimToNull(" \t\n "));
13684
}
13785
}

0 commit comments

Comments
 (0)