diff --git a/docs/visionary_design/images/services_macrange.png b/docs/visionary_design/images/services_macrange.png index a496a64f6..50430fe9d 100644 Binary files a/docs/visionary_design/images/services_macrange.png and b/docs/visionary_design/images/services_macrange.png differ diff --git a/docs/visionary_design/images/services_macstate.png b/docs/visionary_design/images/services_macstate.png index e08ed8245..03450f604 100644 Binary files a/docs/visionary_design/images/services_macstate.png and b/docs/visionary_design/images/services_macstate.png differ diff --git a/docs/visionary_design/mac_manager.adoc b/docs/visionary_design/mac_manager.adoc index 0fffb3444..d754b1e69 100644 Binary files a/docs/visionary_design/mac_manager.adoc and b/docs/visionary_design/mac_manager.adoc differ diff --git a/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteConfiguration.java b/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteConfiguration.java index 6674987d6..dff0ef958 100644 --- a/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteConfiguration.java +++ b/lib/src/main/java/com/futurewei/alcor/common/db/ignite/IgniteConfiguration.java @@ -80,7 +80,7 @@ public IgniteClient igniteClientInstance() { logger.log(Level.WARNING, "Unexpected failure:" + e.getMessage()); } - Assert.notNull(igniteClient, "IgniteClient is null"); + //Assert.notNull(igniteClient, "IgniteClient is null"); return igniteClient; } diff --git a/lib/src/main/java/com/futurewei/alcor/common/repo/ICacheRepository.java b/lib/src/main/java/com/futurewei/alcor/common/repo/ICacheRepository.java index 721fbe294..02c565d8f 100644 --- a/lib/src/main/java/com/futurewei/alcor/common/repo/ICacheRepository.java +++ b/lib/src/main/java/com/futurewei/alcor/common/repo/ICacheRepository.java @@ -16,9 +16,7 @@ package com.futurewei.alcor.common.repo; -import com.futurewei.alcor.common.exception.CacheException; -import com.futurewei.alcor.common.exception.ResourceNotFoundException; - +import com.futurewei.alcor.common.db.CacheException; import java.util.Map; public interface ICacheRepository { diff --git a/pom.xml b/pom.xml index 310808a23..357f1cb09 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,13 @@ com.futurewei.alcor.controller AlcorController 0.1.0-SNAPSHOT - jar + + services/node_manager + services/node_manager + services/node_manager + services/nodemanager + + pom 1.8 diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/config/RedisConfiguration.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/config/RedisConfiguration.java index 0f4df8ab6..6b0938cbb 100644 --- a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/config/RedisConfiguration.java +++ b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/config/RedisConfiguration.java @@ -22,8 +22,8 @@ import com.futurewei.alcor.common.service.RedisListener; import com.futurewei.alcor.macmanager.entity.MacRange; import com.futurewei.alcor.macmanager.entity.MacState; -import com.futurewei.alcor.macmanager.service.implement.RedisMacRangePublisherServiceImpl; -import com.futurewei.alcor.macmanager.service.implement.RedisPublisherServiceImpl; +import com.futurewei.alcor.macmanager.service.implement.redis.RedisMacRangePublisherServiceImpl; +import com.futurewei.alcor.macmanager.service.implement.redis.RedisPublisherServiceImpl; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.context.annotation.Bean; diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/controller/MacController.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/controller/MacController.java index 5d0415639..761f4a9a0 100644 --- a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/controller/MacController.java +++ b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/controller/MacController.java @@ -29,6 +29,8 @@ import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; +import java.util.Collection; +import java.util.HashMap; import java.util.Map; import static org.springframework.web.bind.annotation.RequestMethod.*; @@ -104,7 +106,7 @@ public MacStateJson updateMacState(@PathVariable String macaddress, @RequestBody @RequestMapping( method = DELETE, value = {"/macs/{macaddress}", "/v4/macs/{macaddress}"}) - public ResponseId deleteMacAllocation(@PathVariable String macaddress) throws Exception { + public String deleteMacAllocation(@PathVariable String macaddress) throws Exception { String macAddress = null; try { RestPreconditionsUtil.verifyParameterNotNullorEmpty(macaddress); @@ -112,7 +114,7 @@ public ResponseId deleteMacAllocation(@PathVariable String macaddress) throws Ex } catch (ParameterNullOrEmptyException e) { throw new Exception(e); } - return new ResponseId(macAddress); + return "{mac_address: " + macAddress + "}"; } @RequestMapping( @@ -139,12 +141,11 @@ public MacRangeJson getMacRangeByMacRangeId(@PathVariable String rangeid) throws @RequestMapping( method = GET, value = {"/macs/ranges", "/v4/macs/ranges"}) - public Map getAllMacRanges() throws Exception { - - Map macRanges = null; + public Map> getAllMacRanges() throws Exception { + Map macRanges; + HashMap> map = new HashMap>(); try { macRanges = service.getAllMacRanges(); - } catch (Exception e) { //TODO: REST error code throw new Exception(e); @@ -152,9 +153,10 @@ public Map getAllMacRanges() throws Exception { if (macRanges == null) { //TODO: REST error code - return macRanges; - } - return macRanges; + map.put("mac_ranges", null); + } else + map.put("mac_ranges", macRanges.values()); + return map; } @RequestMapping( @@ -209,6 +211,6 @@ public ResponseId deleteMacRange(@PathVariable String rangeid) throws Exception } catch (ParameterNullOrEmptyException e) { throw new Exception(e); } - return new ResponseId(rangeid); + return new ResponseId(rangeId); } } diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/MacRangeRepository.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/MacRangeRepository.java new file mode 100644 index 000000000..0cb055fa1 --- /dev/null +++ b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/MacRangeRepository.java @@ -0,0 +1,99 @@ +/*Copyright 2019 The Alcor Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +package com.futurewei.alcor.macmanager.dao; + +import com.futurewei.alcor.common.db.CacheException; +import com.futurewei.alcor.common.db.CacheFactory; +import com.futurewei.alcor.common.db.ICache; +import com.futurewei.alcor.common.repo.ICacheRepository; +import com.futurewei.alcor.macmanager.entity.MacRange; +import com.futurewei.alcor.macmanager.entity.MacState; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.stereotype.Repository; + +import javax.annotation.PostConstruct; +import java.util.HashMap; +import java.util.Map; + +@Repository +@ComponentScan(value = "com.futurewei.alcor.common.db") +public class MacRangeRepository implements ICacheRepository { + private static final Logger logger = LoggerFactory.getLogger(MacRangeRepository.class); + private ICache cache; + + @Autowired + public MacRangeRepository(CacheFactory cacheFactory) { + cache = cacheFactory.getCache(MacRange.class); + } + + public ICache getCache() { + return cache; + } + + @PostConstruct + private void init() { + logger.info("MacRangeRepository init: Done"); + } + + @Override + public MacRange findItem(String rangeId) throws CacheException { + MacRange macRange = null; + try { + macRange = cache.get(rangeId); + } catch (CacheException e) { + logger.error("MacRangeRepository findItem() exception:", e); + throw e; + } + return macRange; + } + + @Override + public Map findAllItems() throws CacheException { + HashMap hashMap = new HashMap(); + try { + hashMap = new HashMap(cache.getAll()); + } catch (CacheException e) { + logger.error("MacRangeRepository findAllItems() exception:", e); + throw e; + } + + return hashMap; + } + + @Override + public void addItem(MacRange macRange) throws CacheException { + try { + cache.put(macRange.getRangeId(), macRange); + logger.info("MacRangeRepository addItem() {}: ", macRange.getRangeId()); + } catch (CacheException e) { + logger.error("MacRangeRepository addItem() exception:", e); + throw e; + } + } + + @Override + public void deleteItem(String rangeId) throws CacheException { + try { + cache.remove(rangeId); + logger.info("MacRangeRepository deleteItem() {}: ", rangeId); + } catch (CacheException e) { + logger.error("MacRangeRepository deleteItem() exception:", e); + throw e; + } + } +} \ No newline at end of file diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/MacRepository.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/MacStateRepository.java similarity index 50% rename from services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/MacRepository.java rename to services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/MacStateRepository.java index 359232807..26cca96ee 100644 --- a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/MacRepository.java +++ b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/MacStateRepository.java @@ -15,29 +15,29 @@ package com.futurewei.alcor.macmanager.dao; -import com.futurewei.alcor.common.exception.CacheException; -import com.futurewei.alcor.common.logging.Logger; -import com.futurewei.alcor.common.logging.LoggerFactory; -import com.futurewei.alcor.common.repo.ICache; +import com.futurewei.alcor.common.db.CacheException; +import com.futurewei.alcor.common.db.CacheFactory; +import com.futurewei.alcor.common.db.ICache; import com.futurewei.alcor.common.repo.ICacheRepository; -import com.futurewei.alcor.common.service.CacheFactory; import com.futurewei.alcor.macmanager.entity.MacState; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.context.annotation.ComponentScan; import org.springframework.stereotype.Repository; import javax.annotation.PostConstruct; +import java.util.HashMap; import java.util.Map; -import java.util.logging.Level; @Repository -@ConditionalOnBean(CacheFactory.class) -public class MacRepository implements ICacheRepository { - private static final Logger logger = LoggerFactory.getLogger(); +@ComponentScan(value = "com.futurewei.alcor.common.db") +public class MacStateRepository implements ICacheRepository { + private static final Logger logger = LoggerFactory.getLogger(MacStateRepository.class); private ICache cache; @Autowired - public MacRepository(CacheFactory cacheFactory) { + public MacStateRepository(CacheFactory cacheFactory) { cache = cacheFactory.getCache(MacState.class); } @@ -47,28 +47,52 @@ public ICache getCache() { @PostConstruct private void init() { - logger.log(Level.INFO, "MacRepository init completed"); + logger.info("MacState repository init: Done"); } @Override public MacState findItem(String macAddress) throws CacheException { - return cache.get(macAddress); + MacState macState = null; + try { + macState = cache.get(macAddress); + } catch (CacheException e) { + logger.error("MacStateRepository findItem() exception:", e); + throw e; + } + return macState; } @Override public Map findAllItems() throws CacheException { - return cache.getAll(); + HashMap hashMap = new HashMap(); + try { + hashMap = new HashMap(cache.getAll()); + } catch (CacheException e) { + logger.error("MacStateRepository findAllItems() exception:", e); + throw e; + } + return hashMap; } @Override public void addItem(MacState macState) throws CacheException { - logger.log(Level.INFO, "Add mac state, mac_state:" + macState.getMacAddress()); - cache.put(macState.getMacAddress(), macState); + try { + cache.put(macState.getMacAddress(), macState); + logger.info("MacStateRepository addItem() {}: ", macState.getMacAddress()); + } catch (CacheException e) { + logger.error("MacStateRepository addItem() exception:", e); + throw e; + } } @Override public void deleteItem(String macAddress) throws CacheException { - logger.log(Level.INFO, "Delete mac state, mac address:" + macAddress); - cache.remove(macAddress); + try { + cache.remove(macAddress); + logger.info("MacStateRepository deleteItem() {}: ", macAddress); + } catch (CacheException e) { + logger.error("MacStateRepository deleteItem() exception:", e); + throw e; + } } -} \ No newline at end of file +} diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/MacPoolRedisRepository.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/redis/MacPoolRedisRepository.java similarity index 80% rename from services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/MacPoolRedisRepository.java rename to services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/redis/MacPoolRedisRepository.java index ba9452665..bdbf1bf0d 100644 --- a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/MacPoolRedisRepository.java +++ b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/redis/MacPoolRedisRepository.java @@ -12,7 +12,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package com.futurewei.alcor.macmanager.dao; +package com.futurewei.alcor.macmanager.dao.redis; import com.futurewei.alcor.common.logging.Logger; import com.futurewei.alcor.common.logging.LoggerFactory; @@ -46,7 +46,7 @@ private void init() { } @Override - public String findItem(String value) { + public synchronized String findItem(String value) { if (setOperations.isMember(KEY, value)) return value; else @@ -54,24 +54,28 @@ public String findItem(String value) { } @Override - public Map findAllItems() { + public synchronized Map findAllItems() { return (Map) setOperations.members(KEY); } @Override - public void addItem(String newItem) { + public synchronized void addItem(String newItem) { Logger logger = LoggerFactory.getLogger(); logger.log(Level.INFO, newItem); - setOperations.add(KEY, newItem); + if (setOperations.isMember(KEY, newItem) == false) + setOperations.add(KEY, newItem); } @Override - public void deleteItem(String value) { + public synchronized void deleteItem(String value) { setOperations.remove(KEY, value); } - public String getItem() { - + public synchronized String getItem() { return (String) setOperations.randomMember(KEY); } + + public synchronized long getSize() { + return setOperations.size(KEY); + } } diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/MacRangeRedisRepository.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/redis/MacRangeRedisRepository.java similarity index 83% rename from services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/MacRangeRedisRepository.java rename to services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/redis/MacRangeRedisRepository.java index 2b14c9ba8..a961f6ff3 100644 --- a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/MacRangeRedisRepository.java +++ b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/redis/MacRangeRedisRepository.java @@ -12,7 +12,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package com.futurewei.alcor.macmanager.dao; +package com.futurewei.alcor.macmanager.dao.redis; import com.futurewei.alcor.common.logging.Logger; import com.futurewei.alcor.common.logging.LoggerFactory; @@ -48,30 +48,29 @@ private void init() { } @Override - public MacRange findItem(String id) { + public synchronized MacRange findItem(String id) { return (MacRange) hashOperations.get(KEY, id); } @Override - public Map findAllItems() { - System.out.print("test" + KEY); + public synchronized Map findAllItems() { return hashOperations.entries(KEY); } @Override - public void addItem(MacRange newItem) { + public synchronized void addItem(MacRange newItem) { Logger logger = LoggerFactory.getLogger(); logger.log(Level.INFO, "mac address:" + newItem.getRangeId()); - hashOperations.put(KEY, newItem.getRangeId(), newItem); + hashOperations.putIfAbsent(KEY, newItem.getRangeId(), newItem); } @Override - public void deleteItem(String id) { + public synchronized void deleteItem(String id) { hashOperations.delete(KEY, id); } - public void updateItem(MacRange newItem) { + public synchronized void updateItem(MacRange newItem) { hashOperations.put(KEY, newItem.getRangeId(), newItem); } } diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/MacRedisRepository.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/redis/MacStateRedisRepository.java similarity index 74% rename from services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/MacRedisRepository.java rename to services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/redis/MacStateRedisRepository.java index 8eb47a6af..2a1e02c66 100644 --- a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/MacRedisRepository.java +++ b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/dao/redis/MacStateRedisRepository.java @@ -13,7 +13,7 @@ limitations under the License. */ -package com.futurewei.alcor.macmanager.dao; +package com.futurewei.alcor.macmanager.dao.redis; import com.futurewei.alcor.common.logging.Logger; import com.futurewei.alcor.common.logging.LoggerFactory; @@ -29,7 +29,7 @@ import java.util.logging.Level; @Repository -public class MacRedisRepository implements ICacheRepository { +public class MacStateRedisRepository implements ICacheRepository { private String KEY = "mac_state"; @@ -38,7 +38,7 @@ public class MacRedisRepository implements ICacheRepository { private HashOperations hashOperations; @Autowired - public MacRedisRepository(RedisTemplate redisTemplate) { + public MacStateRedisRepository(RedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } @@ -49,43 +49,34 @@ private void init() { } @Override - public MacState findItem(String id) { + public synchronized MacState findItem(String id) { return (MacState) hashOperations.get(KEY, id); } @Override - public Map findAllItems() { + public synchronized Map findAllItems() { return hashOperations.entries(KEY); } @Override - public void addItem(MacState newItem) { + public synchronized void addItem(MacState newItem) { Logger logger = LoggerFactory.getLogger(); logger.log(Level.INFO, "mac address:" + newItem.getMacAddress()); - hashOperations.put(KEY, newItem.getMacAddress(), newItem); + hashOperations.putIfAbsent(KEY, newItem.getMacAddress(), newItem); } @Override - public void deleteItem(String id) { + public synchronized void deleteItem(String id) { hashOperations.delete(KEY, id); } - public void updateItem(MacState newItem) { + public synchronized void updateItem(MacState newItem) { hashOperations.put(KEY, newItem.getMacAddress(), newItem); } - public MacState findMac(String id) { + public synchronized MacState findMac(String id) { return (MacState) hashOperations.get(KEY, id); } - - public void setKey(String key) { - KEY = key; - } - - public boolean exisingOui(String oui) { - - return redisTemplate.hasKey(oui); - } } diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/entity/MacRange.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/entity/MacRange.java index 34156689a..12d50496c 100644 --- a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/entity/MacRange.java +++ b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/entity/MacRange.java @@ -49,8 +49,10 @@ public MacRange(String rangeId, String from, String to, String state) { public void createDefault(String oui) { rangeId = MacUtil.DEFAULT_RANGE; - from = new MacAddress(oui, MacAddress.longToMac(0)).getMacAddress(); - to = new MacAddress(oui, MacAddress.longToMac((long)Math.pow(2,MacAddress.NIC_LENGTH))).getMacAddress(); + String strFrom = MacAddress.longToMac(0); + String strTo = MacAddress.longToMac((long)Math.pow(2,MacAddress.NIC_LENGTH) - 1); + from = new MacAddress(oui, strFrom).getMacAddress(); + to = new MacAddress(oui, strTo).getMacAddress(); state = MacUtil.MAC_RANGE_STATE_ACTIVE; } } diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/entity/MacRangeJson.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/entity/MacRangeJson.java index 693a6c5c5..a9ce11273 100644 --- a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/entity/MacRangeJson.java +++ b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/entity/MacRangeJson.java @@ -14,11 +14,13 @@ */ package com.futurewei.alcor.macmanager.entity; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; @Data public class MacRangeJson { + @JsonProperty("mac_range") private MacRange macRange; public MacRangeJson() { diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/entity/MacState.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/entity/MacState.java index 0da070a16..17cfc70a0 100644 --- a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/entity/MacState.java +++ b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/entity/MacState.java @@ -35,23 +35,23 @@ public class MacState implements Serializable { @JsonProperty("port_id") private String portId; - @JsonProperty("active") - private String active; + @JsonProperty("state") + private String state; public MacState() { } public MacState(MacState state) { - this(state.macAddress, state.projectId, state.vpcId, state.portId, state.active); + this(state.macAddress, state.projectId, state.vpcId, state.portId, state.state); } - public MacState(String macAddress, String projectId, String vpcId, String portId, String active) { + public MacState(String macAddress, String projectId, String vpcId, String portId, String state) { this.macAddress = macAddress; this.projectId = projectId; this.vpcId = vpcId; this.portId = portId; - this.active = active; + this.state = state; } } diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/entity/MacStateJson.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/entity/MacStateJson.java index 0e15f59ce..e45cd6156 100644 --- a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/entity/MacStateJson.java +++ b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/entity/MacStateJson.java @@ -15,10 +15,13 @@ */ package com.futurewei.alcor.macmanager.entity; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; @Data public class MacStateJson { + + @JsonProperty("mac_state") private MacState macState; public MacStateJson() { diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/exception/InvalidMacRangeException.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/exception/InvalidMacRangeException.java new file mode 100644 index 000000000..5b2f17e96 --- /dev/null +++ b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/exception/InvalidMacRangeException.java @@ -0,0 +1,32 @@ +/*Copyright 2019 The Alcor Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +package com.futurewei.alcor.macmanager.exception; + +public class InvalidMacRangeException extends Exception { + public InvalidMacRangeException() { + } + + public InvalidMacRangeException(String message) { + super(message); + } + + public InvalidMacRangeException(String message, Throwable cause) { + super(message, cause); + } + + public InvalidMacRangeException(Throwable cause) { + super(cause); + } +} diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/exception/RetryLimitExceedException.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/exception/RetryLimitExceedException.java new file mode 100644 index 000000000..c4c7c4f08 --- /dev/null +++ b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/exception/RetryLimitExceedException.java @@ -0,0 +1,32 @@ +/*Copyright 2019 The Alcor Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +package com.futurewei.alcor.macmanager.exception; + +public class RetryLimitExceedException extends Exception { + public RetryLimitExceedException() { + } + + public RetryLimitExceedException(String message) { + super(message); + } + + public RetryLimitExceedException(String message, Throwable cause) { + super(message, cause); + } + + public RetryLimitExceedException(Throwable cause) { + super(cause); + } +} diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/exception/UniquenessViolationException.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/exception/UniquenessViolationException.java index a738a7adc..78e081df4 100644 --- a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/exception/UniquenessViolationException.java +++ b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/exception/UniquenessViolationException.java @@ -15,8 +15,6 @@ package com.futurewei.alcor.macmanager.exception; public class UniquenessViolationException extends Exception { - private static final long serialVersionUID = 1L; - public UniquenessViolationException() { } diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/MacService.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/MacService.java index 5bbcbdd33..4567514a8 100644 --- a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/MacService.java +++ b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/MacService.java @@ -2,14 +2,11 @@ import com.futurewei.alcor.macmanager.entity.MacRange; import com.futurewei.alcor.macmanager.entity.MacState; -import com.futurewei.alcor.macmanager.exception.UniquenessViolationException; -import java.util.Hashtable; import java.util.Map; -import java.util.Vector; public interface MacService { - MacState getMacStateByMacAddress(String macAddress); + MacState getMacStateByMacAddress(String macAddress) throws Exception; MacState createMacState(MacState macState) throws Exception; @@ -17,9 +14,9 @@ public interface MacService { String releaseMacState(String macAddress) throws Exception; - MacRange getMacRangeByMacRangeId(String macRangeId); + MacRange getMacRangeByMacRangeId(String macRangeId) throws Exception; - Map getAllMacRanges(); + Map getAllMacRanges() throws Exception; MacRange createMacRange(MacRange macRange) throws Exception; diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/MacRedisServiceImpl.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/MacRedisServiceImpl.java deleted file mode 100644 index 09bfe4362..000000000 --- a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/MacRedisServiceImpl.java +++ /dev/null @@ -1,193 +0,0 @@ -/*Copyright 2019 The Alcor Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ -package com.futurewei.alcor.macmanager.service.implement; - -import com.futurewei.alcor.common.exception.ResourceNotFoundException; -import com.futurewei.alcor.macmanager.dao.MacPoolRedisRepository; -import com.futurewei.alcor.macmanager.dao.MacRangeRedisRepository; -import com.futurewei.alcor.macmanager.dao.MacRedisRepository; -import com.futurewei.alcor.macmanager.entity.MacAddress; -import com.futurewei.alcor.macmanager.entity.MacRange; -import com.futurewei.alcor.macmanager.entity.MacState; -import com.futurewei.alcor.macmanager.exception.UniquenessViolationException; -import com.futurewei.alcor.macmanager.service.MacService; -import com.futurewei.alcor.macmanager.utils.MacUtil; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Map; -import java.util.Vector; -import java.util.concurrent.ThreadLocalRandom; - -@Service -public class MacRedisServiceImpl implements MacService { - final String DELIMITER = "/"; - - @Autowired - private MacRangeRedisRepository macRangeRedisRepository; - - @Autowired - private MacPoolRedisRepository macPoolRedisRepository; - - @Autowired - private MacRedisRepository macRedisRepository; - - @Value("${macmanager.oui}") - private String oui; - - private HashMap macRanges = new HashMap(); - - public MacState getMacStateByMacAddress(String macAddress) { - MacState macState = macRedisRepository.findItem(macAddress); - return macState; - } - - public MacState createMacState(MacState macState) throws Exception { - MacAddress macAddress = new MacAddress(); - String strMacAddress = allocateMacState(macState); - if (strMacAddress != null) { - macState.setMacAddress(strMacAddress); - macRedisRepository.addItem(macState); - } else { - String nic = generateNic(); - macAddress.setOui(oui); - macAddress.setNic(nic); - macState.setMacAddress(macAddress.getMacAddress()); - MacState macState2 = macRedisRepository.findItem(macAddress.getMacAddress()); - if (macRedisRepository.findItem(macAddress.getMacAddress()) != null) - throw (new UniquenessViolationException("This mac address is not unique!!"+macAddress.getMacAddress()+macState2.getProjectId())); - else - macRedisRepository.addItem(macState); - } - return macState; - } - - @Override - public MacState updateMacState(String macAddress, MacState macState) throws Exception { - if(macState != null) - macRedisRepository.updateItem(macState); - return macState; - } - - public String releaseMacState(String macAddress) throws Exception { - MacState macState = macRedisRepository.findItem(macAddress); - if (macState == null) { - ResourceNotFoundException e = new ResourceNotFoundException("MAC address Not Found"); - throw e; - } else { - macPoolRedisRepository.addItem(macAddress); - macRedisRepository.deleteItem(macAddress); - } - return macAddress; - } - - @Override - public MacRange getMacRangeByMacRangeId(String macRangeId) { - MacRange macRange = macRangeRedisRepository.findItem(macRangeId); - return macRange; - } - - @Override - public Map getAllMacRanges() { - Hashtable macRanges = (Hashtable) macRangeRedisRepository.findAllItems(); - return macRanges; - } - - @Override - public MacRange createMacRange(MacRange macRange) throws Exception { - if (macRange != null) { - macRangeRedisRepository.addItem(macRange); - } - return macRange; - } - - @Override - public MacRange updateMacRange(MacRange macRange) throws Exception { - if (macRange != null) { - macRangeRedisRepository.updateItem(macRange); - } - return macRange; - } - - @Override - public String deleteMacRange(String rangeId) throws Exception { - if (rangeId != null) { - macRangeRedisRepository.deleteItem(rangeId); - } - return rangeId; - } - - private String allocateMacState(MacState macState) { - String strMacAddress = macPoolRedisRepository.getItem(); - if (strMacAddress != null) { - macPoolRedisRepository.deleteItem(strMacAddress); - } - return strMacAddress; - } - - private String generateNic() { - String nic = null; - MacAddress macAddress = new MacAddress(); - long randomNic; - Long from = (long) 0; - Long to = (long) Math.pow(2, MacAddress.NIC_LENGTH); - - MacRange macRange = getMacRange(); - if (macRange != null) { - from = MacAddress.macToLong(new MacAddress(macRange.getFrom()).getNic()); - to = MacAddress.macToLong(new MacAddress(macRange.getTo()).getNic()); - } - - while (nic == null) { - randomNic = ThreadLocalRandom.current().nextLong(from, to); - String nicTemp = MacAddress.hexToMac(Long.toHexString(randomNic)); - macAddress.setNic(nicTemp); - if (macRedisRepository.findMac(macAddress.getMacAddress()) == null && macPoolRedisRepository.findItem(macAddress.getMacAddress()) == null) { - nic = nicTemp; - } - } - return nic; - } - - private MacRange getMacRange() { - MacRange macRange = new MacRange(); - Vector activeMacRanges = getActiveMacRanges(); - int randomIndex = ThreadLocalRandom.current().nextInt(0, activeMacRanges.size()); - return activeMacRanges.get(randomIndex); - } - - public Vector getActiveMacRanges() { - Vector activeMacRanges = new Vector(); - - macRanges = (HashMap) macRangeRedisRepository.findAllItems(); - int nSize = macRanges.size(); - if (nSize > 0) { - for (Map.Entry entry : macRanges.entrySet()) { - if (entry.getValue().getState().equals("Active")) { - activeMacRanges.add(entry.getValue()); - } - } - } else if (macRanges != null) { - MacRange newRange = new MacRange(); - newRange.createDefault(oui); - macRangeRedisRepository.addItem(newRange); - activeMacRanges.add(newRange); - } - return activeMacRanges; - } -} \ No newline at end of file diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/MacServiceImpl.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/MacServiceImpl.java new file mode 100644 index 000000000..88b94e97e --- /dev/null +++ b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/MacServiceImpl.java @@ -0,0 +1,331 @@ +/*Copyright 2019 The Alcor Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +package com.futurewei.alcor.macmanager.service.implement; + +import com.futurewei.alcor.common.exception.ParameterNullOrEmptyException; +import com.futurewei.alcor.common.exception.ParameterUnexpectedValueException; +import com.futurewei.alcor.common.exception.ResourceNotFoundException; +import com.futurewei.alcor.macmanager.dao.MacRangeRepository; +import com.futurewei.alcor.macmanager.dao.MacStateRepository; +import com.futurewei.alcor.macmanager.entity.MacAddress; +import com.futurewei.alcor.macmanager.entity.MacRange; +import com.futurewei.alcor.macmanager.entity.MacState; +import com.futurewei.alcor.macmanager.exception.InvalidMacRangeException; +import com.futurewei.alcor.macmanager.exception.RetryLimitExceedException; +import com.futurewei.alcor.macmanager.exception.UniquenessViolationException; +import com.futurewei.alcor.macmanager.service.MacService; +import com.futurewei.alcor.macmanager.utils.MacUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ThreadLocalRandom; + +@Service +public class MacServiceImpl implements MacService { + private static final Logger logger = LoggerFactory.getLogger(MacServiceImpl.class); + static public Hashtable activeMacRanges = new Hashtable(); + final String DELIMITER = "/"; + + @Autowired + private MacRangeRepository macRangeRepository; + + @Autowired + private MacStateRepository macStateRepository; + + @Value("${macmanager.oui}") + private String oui; + + @Value("${macmanager.pool.size}") + private long nMacPoolSize; + + @Value("${macmanager.retrylimit}") + private long nRetryLimit; + + private Set macPool; + + public MacState getMacStateByMacAddress(String macAddress) throws Exception { + MacState macState = null; + if ( macAddress == null) + throw (new ParameterNullOrEmptyException(MacUtil.MAC_EXCEPTION_PARAMETER_NULL_EMPTY)); + try{ + macState = macStateRepository.findItem(macAddress); + } catch(Exception e) + { + throw e; + } + return macState; + } + + public MacState createMacState(MacState macState) throws Exception { + if ( macState == null) + throw (new ParameterNullOrEmptyException(MacUtil.MAC_EXCEPTION_PARAMETER_NULL_EMPTY)); + MacAddress macAddress = new MacAddress(); + if (macState.getState() == null) + macState.setState(MacUtil.MAC_STATE_ACTIVE); + else if (macState.getState().trim().length() == 0) + macState.setState(MacUtil.MAC_STATE_ACTIVE); + if (macPool.size() < (nMacPoolSize - 10)) { + CompletableFuture completableFuture = CompletableFuture.supplyAsync(() -> { + long n = 0; + try { + n = generateMacInPool(20); + } catch (Exception e) { + + } + return n; + }); + long l = completableFuture.get(); + completableFuture.thenAccept(System.out::println); + completableFuture.join(); + logger.info("{} New MAC addresses were created.", l); + } + + String strMacAddress = allocateMacState(macState); + if (strMacAddress != null) { + macState.setMacAddress(strMacAddress); + macStateRepository.addItem(macState); + } else { + try { + String nic = generateNic(); + macAddress.setOui(oui); + macAddress.setNic(nic); + macState.setMacAddress(macAddress.getMacAddress()); + MacState macState2 = macStateRepository.findItem(macAddress.getMacAddress()); + if (macStateRepository.findItem(macAddress.getMacAddress()) != null) + throw (new UniquenessViolationException(MacUtil.MAC_EXCEPTION_UNIQUENESSSS_VILOATION + macAddress.getMacAddress() + macState2.getProjectId())); + else + macStateRepository.addItem(macState); + } catch (Exception e) { + throw e; + } + } + return macState; + } + + @Override + public MacState updateMacState(String macAddress, MacState macState) throws Exception { + if (macAddress == null || macState == null) + throw (new ParameterNullOrEmptyException(MacUtil.MAC_EXCEPTION_PARAMETER_NULL_EMPTY)); + if(macAddress.equals(macState.getMacAddress()) == false) + throw (new ParameterUnexpectedValueException(MacUtil.MAC_EXCEPTION_PARAMETER_INVALID)); + if (macStateRepository.findItem(macAddress) != null) { + macStateRepository.addItem(macState); + } else { + throw (new ResourceNotFoundException(MacUtil.MAC_EXCEPTION_MAC_NOT_EXISTING)); + } + return macState; + } + + public String releaseMacState(String macAddress) throws Exception { + if (macAddress == null) + throw (new ParameterNullOrEmptyException(MacUtil.MAC_EXCEPTION_PARAMETER_NULL_EMPTY)); + MacState macState = macStateRepository.findItem(macAddress); + if (macState == null) { + throw (new ResourceNotFoundException(MacUtil.MAC_EXCEPTION_MAC_NOT_EXISTING)); + } else { + try { + macStateRepository.deleteItem(macAddress); + macPool.add(macAddress); + }catch (Exception e) + { + throw e; + } + } + return macState.getMacAddress(); + } + + @Override + public MacRange getMacRangeByMacRangeId(String macRangeId) throws Exception { + if (macRangeId == null) + throw (new ParameterNullOrEmptyException(MacUtil.MAC_EXCEPTION_PARAMETER_NULL_EMPTY)); + MacRange macRange = null; + try{ + macRange = macRangeRepository.findItem(macRangeId); + } catch(Exception e) + { + throw e; + } + return macRange; + } + + @Override + public Map getAllMacRanges() throws Exception { + Hashtable macRanges = new Hashtable(); + try{ + macRanges.putAll(macRangeRepository.findAllItems()); + }catch (Exception e){ + throw e; + } + return macRanges; + } + + @Override + public MacRange createMacRange(MacRange macRange) throws Exception { + if (macRange == null) + throw (new ParameterNullOrEmptyException(MacUtil.MAC_EXCEPTION_PARAMETER_NULL_EMPTY)); + if (isValidRange(macRange) == false) + throw (new InvalidMacRangeException(MacUtil.MAC_EXCEPTION_RANGE_VALUE_INVALID)); + try { + macRangeRepository.addItem(macRange); + if (macRange.getState().equals(MacUtil.MAC_RANGE_STATE_ACTIVE)) + activeMacRanges.put(macRange.getRangeId(), macRange); + } catch (Exception e) { + throw e; + } + return macRange; + } + + @Override + public MacRange updateMacRange(MacRange macRange) throws Exception { + if (macRange == null) + throw (new ParameterNullOrEmptyException(MacUtil.MAC_EXCEPTION_PARAMETER_NULL_EMPTY)); + if (isValidRange(macRange) == false) + throw (new InvalidMacRangeException(MacUtil.MAC_EXCEPTION_RANGE_VALUE_INVALID)); + try { + macRangeRepository.deleteItem(macRange.getRangeId()); + macRangeRepository.addItem(macRange); + if (macRange.getState().equals(MacUtil.MAC_RANGE_STATE_INACTIVE) && activeMacRanges.containsKey(macRange.getRangeId())) + activeMacRanges.remove(macRange.getRangeId(), macRange); + else if (macRange.getState().equals(MacUtil.MAC_RANGE_STATE_ACTIVE) && activeMacRanges.containsKey(macRange.getRangeId()) == false) + activeMacRanges.put(macRange.getRangeId(), macRange); + } catch(Exception e) + { + throw e; + } + return macRange; + } + + @Override + public String deleteMacRange(String rangeId) throws Exception { + if (rangeId == null) + throw (new ParameterNullOrEmptyException(MacUtil.MAC_EXCEPTION_PARAMETER_NULL_EMPTY)); + try{ + macRangeRepository.deleteItem(rangeId); + activeMacRanges.remove(rangeId); + }catch (Exception e) + { + throw e; + } + return rangeId; + } + + private String allocateMacState(MacState macState) throws Exception { +// if (macState == null) +// throw (new ParameterNullOrEmptyException(MacUtil.MAC_EXCEPTION_PARAMETER_NULL_EMPTY)); +// try{ +// +// } +// //String strMacAddress = macPool. +// if (strMacAddress != null) { +// // macPool.deleteItem(strMacAddress); +// } + return null; //strMacAddress; + } + + private String generateNic() throws Exception { + String nic = null; + MacAddress macAddress = new MacAddress(); + long randomNic; + Long from = (long) 0; + Long to = (long) Math.pow(2, MacAddress.NIC_LENGTH); + + MacRange macRange = getMacRange(); + if (macRange != null) { + from = MacAddress.macToLong(new MacAddress(macRange.getFrom()).getNic()); + to = MacAddress.macToLong(new MacAddress(macRange.getTo()).getNic()); + } + + int i = 0; + while (nic == null && i < nRetryLimit) { + randomNic = ThreadLocalRandom.current().nextLong(from, to); + String nicTemp = MacAddress.hexToMac(Long.toHexString(randomNic)); + macAddress.setNic(nicTemp); + if ((macStateRepository.findItem(macAddress.getMacAddress()) == null) && (macPool.contains(macAddress.getMacAddress()) == false)) { + nic = nicTemp; + } + i++; + } + if (nic == null) + throw new RetryLimitExceedException(MacUtil.MAC_EXCEPTION_RETRY_LIMIT_EXCEED); + return nic; + } + + private MacRange getMacRange() throws Exception { + MacRange macRange = new MacRange(); + if (activeMacRanges.isEmpty()) + getActiveMacRanges(); + int randomIndex = ThreadLocalRandom.current().nextInt(0, activeMacRanges.size()); + Vector vector = new Vector(activeMacRanges.keySet()); + return activeMacRanges.get(vector.elementAt(randomIndex)); + } + + public void getActiveMacRanges() throws Exception { + Hashtable macRanges = new Hashtable(macRangeRepository.findAllItems()); + if (macRanges == null) + macRanges = new Hashtable(); + int nSize = macRanges.size(); + if (nSize > 0) { + for (Map.Entry entry : macRanges.entrySet()) { + if (entry.getValue().getState().equals(MacUtil.MAC_RANGE_STATE_ACTIVE)) { + activeMacRanges.put(entry.getKey(), entry.getValue()); + } + } + } else if (macRanges != null) { + MacRange newRange = new MacRange(); + newRange.createDefault(oui); + macRangeRepository.addItem(newRange); + activeMacRanges.put(newRange.getRangeId(), newRange); + } + } + + private boolean isValidRange(MacRange macRange) { + String strFrom = macRange.getFrom(); + String strTo = macRange.getTo(); + long from = MacAddress.macToLong(new MacAddress(strFrom).getNic()); + long to = MacAddress.macToLong(new MacAddress(strTo).getNic()); + return from < to; + } + + public long generateMacInPool(int n) throws Exception { + Exception exception = null; + long nReturn = 0; + ArrayList list = new ArrayList(); + if (n < 1) return nReturn; + MacAddress macAddress = new MacAddress(); + for (int i = 0; i < n; i++) { + try { + String nic = generateNic(); + macAddress.setOui(oui); + macAddress.setNic(nic); + String strMacAddress = macAddress.getMacAddress(); + MacState macState = macStateRepository.findItem(strMacAddress); + if (macState == null) { + //macPool.addItem(strMacAddress); + nReturn++; + } + } catch (RetryLimitExceedException e) { + exception = e; + } + } + if (exception != null) + throw exception; + return nReturn; + } +} diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/RedisMacRangePublisherServiceImpl.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/redis/RedisMacRangePublisherServiceImpl.java similarity index 81% rename from services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/RedisMacRangePublisherServiceImpl.java rename to services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/redis/RedisMacRangePublisherServiceImpl.java index 04ba96a4b..ebf5d4ba0 100644 --- a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/RedisMacRangePublisherServiceImpl.java +++ b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/redis/RedisMacRangePublisherServiceImpl.java @@ -12,7 +12,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package com.futurewei.alcor.macmanager.service.implement; +package com.futurewei.alcor.macmanager.service.implement.redis; import com.futurewei.alcor.common.repo.ICachePublisher; import com.futurewei.alcor.macmanager.entity.MacRange; @@ -24,20 +24,20 @@ @Service public class RedisMacRangePublisherServiceImpl implements ICachePublisher { @Autowired - private RedisTemplate redisTemplate2; + private RedisTemplate redisTemplate; @Autowired - private ChannelTopic topic2; + private ChannelTopic topic; public RedisMacRangePublisherServiceImpl() { } public RedisMacRangePublisherServiceImpl(final RedisTemplate redisTemplate, final ChannelTopic topic2) { - this.redisTemplate2 = redisTemplate; - this.topic2 = topic2; + this.redisTemplate = redisTemplate; + this.topic = topic2; } public void publish(final String message) { - redisTemplate2.convertAndSend(topic2.getTopic(), message); + redisTemplate.convertAndSend(topic.getTopic(), message); } } diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/redis/RedisMacServiceImpl.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/redis/RedisMacServiceImpl.java new file mode 100644 index 000000000..b4b246112 --- /dev/null +++ b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/redis/RedisMacServiceImpl.java @@ -0,0 +1,277 @@ +/*Copyright 2019 The Alcor Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +package com.futurewei.alcor.macmanager.service.implement.redis; + +import com.futurewei.alcor.common.exception.ResourceNotFoundException; +import com.futurewei.alcor.macmanager.dao.redis.MacPoolRedisRepository; +import com.futurewei.alcor.macmanager.dao.redis.MacRangeRedisRepository; +import com.futurewei.alcor.macmanager.dao.redis.MacStateRedisRepository; +import com.futurewei.alcor.macmanager.entity.MacAddress; +import com.futurewei.alcor.macmanager.entity.MacRange; +import com.futurewei.alcor.macmanager.entity.MacState; +import com.futurewei.alcor.macmanager.exception.InvalidMacRangeException; +import com.futurewei.alcor.macmanager.exception.RetryLimitExceedException; +import com.futurewei.alcor.macmanager.exception.UniquenessViolationException; +import com.futurewei.alcor.macmanager.service.MacService; +import com.futurewei.alcor.macmanager.utils.MacUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Map; +import java.util.Vector; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ThreadLocalRandom; + +@Service +public class RedisMacServiceImpl implements MacService { + private static final Logger LOG = LoggerFactory.getLogger(RedisMacServiceImpl.class); + static public Hashtable activeMacRanges = new Hashtable(); + final String DELIMITER = "/"; + + @Autowired + private MacRangeRedisRepository macRangeRedisRepository; + + @Autowired + private MacPoolRedisRepository macPoolRedisRepository; + + @Autowired + private MacStateRedisRepository macStateRedisRepository; + + @Value("${macmanager.oui}") + private String oui; + + @Value("${macmanager.pool.size}") + private long nMacPoolSize; + + @Value("${macmanager.retrylimit}") + private long nRetryLimit; + + public MacState getMacStateByMacAddress(String macAddress) { + MacState macState = macStateRedisRepository.findItem(macAddress); + return macState; + } + + public MacState createMacState(MacState macState) throws Exception { + MacAddress macAddress = new MacAddress(); + if (macState.getState() == null) + macState.setState(MacUtil.MAC_STATE_ACTIVE); + else if (macState.getState().trim().length() == 0) + macState.setState(MacUtil.MAC_STATE_ACTIVE); + if (macPoolRedisRepository.getSize() < (nMacPoolSize - 10)) { + CompletableFuture completableFuture = CompletableFuture.supplyAsync(() -> { + long n = 0; + try { + n = generateMacInPool(20); + } catch (Exception e) { + e.printStackTrace(); + } + return n; + }); + long l = completableFuture.get(); + completableFuture.thenAccept(System.out::println); + completableFuture.join(); + LOG.info("{} New MAC addresses were created.", l); + } + + String strMacAddress = allocateMacState(macState); + if (strMacAddress != null) { + macState.setMacAddress(strMacAddress); + macStateRedisRepository.addItem(macState); + } else { + try { + String nic = generateNic(); + macAddress.setOui(oui); + macAddress.setNic(nic); + macState.setMacAddress(macAddress.getMacAddress()); + MacState macState2 = macStateRedisRepository.findItem(macAddress.getMacAddress()); + if (macStateRedisRepository.findItem(macAddress.getMacAddress()) != null) + throw (new UniquenessViolationException(MacUtil.MAC_EXCEPTION_UNIQUENESSSS_VILOATION + macAddress.getMacAddress() + macState2.getProjectId())); + else + macStateRedisRepository.addItem(macState); + } catch (Exception e) { + throw e; + } + } + return macState; + } + + @Override + public MacState updateMacState(String macAddress, MacState macState) throws Exception { + if (macState != null) + macStateRedisRepository.updateItem(macState); + return macState; + } + + public String releaseMacState(String macAddress) throws Exception { + MacState macState = macStateRedisRepository.findItem(macAddress); + if (macState == null) { + ResourceNotFoundException e = new ResourceNotFoundException("MAC address Not Found"); + throw e; + } else { + macStateRedisRepository.deleteItem(macAddress); + macPoolRedisRepository.addItem(macAddress); + } + return macState.getMacAddress(); + } + + @Override + public MacRange getMacRangeByMacRangeId(String macRangeId) { + MacRange macRange = macRangeRedisRepository.findItem(macRangeId); + return macRange; + } + + @Override + public Map getAllMacRanges() { + Map macRanges = macRangeRedisRepository.findAllItems(); + return macRanges; + } + + @Override + public MacRange createMacRange(MacRange macRange) throws Exception { + if (macRange != null) { + if (isValidRange(macRange)) { + macRangeRedisRepository.addItem(macRange); + if (macRange.getState().equals(MacUtil.MAC_RANGE_STATE_ACTIVE)) + activeMacRanges.put(macRange.getRangeId(), macRange); + } else + throw (new InvalidMacRangeException(MacUtil.MAC_EXCEPTION_RANGE_VALUE_INVALID)); + } + return macRange; + } + + @Override + public MacRange updateMacRange(MacRange macRange) throws Exception { + if (macRange != null) { + macRangeRedisRepository.updateItem(macRange); + if (macRange.getState().equals(MacUtil.MAC_RANGE_STATE_INACTIVE) && activeMacRanges.containsKey(macRange.getRangeId())) + activeMacRanges.remove(macRange.getRangeId(), macRange); + else if (macRange.getState().equals(MacUtil.MAC_RANGE_STATE_ACTIVE) && activeMacRanges.containsKey(macRange.getRangeId()) == false) + activeMacRanges.put(macRange.getRangeId(), macRange); + } + return macRange; + } + + @Override + public String deleteMacRange(String rangeId) throws Exception { + if (rangeId != null) { + macRangeRedisRepository.deleteItem(rangeId); + activeMacRanges.remove(rangeId); + } + return rangeId; + } + + private String allocateMacState(MacState macState) { + String strMacAddress = macPoolRedisRepository.getItem(); + if (strMacAddress != null) { + macPoolRedisRepository.deleteItem(strMacAddress); + } + return strMacAddress; + } + + private String generateNic() throws Exception { + String nic = null; + MacAddress macAddress = new MacAddress(); + long randomNic; + Long from = (long) 0; + Long to = (long) Math.pow(2, MacAddress.NIC_LENGTH); + + MacRange macRange = getMacRange(); + if (macRange != null) { + from = MacAddress.macToLong(new MacAddress(macRange.getFrom()).getNic()); + to = MacAddress.macToLong(new MacAddress(macRange.getTo()).getNic()); + } + + int i = 0; + while (nic == null && i < nRetryLimit) { + randomNic = ThreadLocalRandom.current().nextLong(from, to); + String nicTemp = MacAddress.hexToMac(Long.toHexString(randomNic)); + macAddress.setNic(nicTemp); + if (macStateRedisRepository.findMac(macAddress.getMacAddress()) == null && macPoolRedisRepository.findItem(macAddress.getMacAddress()) == null) { + nic = nicTemp; + } + i++; + } + if (nic == null && i >= nRetryLimit) + throw new RetryLimitExceedException(MacUtil.MAC_EXCEPTION_RETRY_LIMIT_EXCEED); + return nic; + } + + private MacRange getMacRange() { + MacRange macRange = new MacRange(); + if (activeMacRanges.isEmpty()) + getActiveMacRanges(); + int randomIndex = ThreadLocalRandom.current().nextInt(0, activeMacRanges.size()); + Vector vector = new Vector(activeMacRanges.keySet()); + return activeMacRanges.get(vector.elementAt(randomIndex)); + } + + public void getActiveMacRanges() { + Hashtable macRanges = new Hashtable(macRangeRedisRepository.findAllItems()); + if (macRanges == null) + macRanges = new Hashtable(); + int nSize = macRanges.size(); + if (nSize > 0) { + for (Map.Entry entry : macRanges.entrySet()) { + if (entry.getValue().getState().equals(MacUtil.MAC_RANGE_STATE_ACTIVE)) { + activeMacRanges.put(entry.getKey(), entry.getValue()); + } + } + } else if (macRanges != null) { + MacRange newRange = new MacRange(); + newRange.createDefault(oui); + macRangeRedisRepository.addItem(newRange); + activeMacRanges.put(newRange.getRangeId(), newRange); + } + } + + private boolean isValidRange(MacRange macRange) { + String strFrom = macRange.getFrom(); + String strTo = macRange.getTo(); + long from = MacAddress.macToLong(new MacAddress(strFrom).getNic()); + long to = MacAddress.macToLong(new MacAddress(strTo).getNic()); + return from < to; + } + + public long generateMacInPool(int n) throws Exception { + Exception exception = null; + long nReturn = 0; + ArrayList list = new ArrayList(); + if (n < 1) return nReturn; + MacAddress macAddress = new MacAddress(); + for (int i = 0; i < n; i++) { + try { + String nic = generateNic(); + macAddress.setOui(oui); + macAddress.setNic(nic); + String strMacAddress = macAddress.getMacAddress(); + MacState macState = macStateRedisRepository.findItem(strMacAddress); + if (macState == null) { + macPoolRedisRepository.addItem(strMacAddress); + nReturn++; + } + } catch (RetryLimitExceedException e) { + exception = e; + } + } + if (exception != null) + throw exception; + return nReturn; + } +} \ No newline at end of file diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/RedisPublisherServiceImpl.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/redis/RedisPublisherServiceImpl.java similarity index 95% rename from services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/RedisPublisherServiceImpl.java rename to services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/redis/RedisPublisherServiceImpl.java index 6dceab39d..0bca8552f 100644 --- a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/RedisPublisherServiceImpl.java +++ b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/service/implement/redis/RedisPublisherServiceImpl.java @@ -14,7 +14,7 @@ limitations under the License. */ -package com.futurewei.alcor.macmanager.service.implement; +package com.futurewei.alcor.macmanager.service.implement.redis; import com.futurewei.alcor.common.repo.ICachePublisher; import com.futurewei.alcor.macmanager.entity.MacState; diff --git a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/utils/MacUtil.java b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/utils/MacUtil.java index 6ded886bd..9d7d24bb8 100644 --- a/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/utils/MacUtil.java +++ b/services/mac_manager/src/main/java/com/futurewei/alcor/macmanager/utils/MacUtil.java @@ -16,10 +16,18 @@ public class MacUtil { public static final String MAC_STATE_ACTIVE = "Active"; - public static final String MAC_STATE_INACTIVE= "Inactive"; + public static final String MAC_STATE_INACTIVE = "Inactive"; public static final String DEFAULT_RANGE = "range0"; public static final String MAC_RANGE_STATE_ACTIVE = "Active"; public static final String MAC_RANGE_STATE_INACTIVE = "Inactive"; public static final String MAC_RANGE_STATE_EXCLUDE = "Exclude"; + + public static final String MAC_EXCEPTION_UNIQUENESSSS_VILOATION = "This mac address is not unique!!"; + public static final String MAC_EXCEPTION_RETRY_LIMIT_EXCEED = "It exceeded the limit of retry for to create a MAC. Please check active MAC ranges."; + public static final String MAC_EXCEPTION_RANGE_VALUE_INVALID = "MAC range is not vaild. Ranges' start value should be less than end value."; + public static final String MAC_EXCEPTION_MAC_NOT_EXISTING = "Non existing MAC address."; + public static final String MAC_EXCEPTION_PARAMETER_NULL_EMPTY = "Parameter is null or empty"; + public static final String MAC_EXCEPTION_PARAMETER_INVALID = "Parameter data format or value is not valid"; + } diff --git a/services/mac_manager/src/main/resources/application.properties b/services/mac_manager/src/main/resources/application.properties index 9407bde35..b53a07660 100644 --- a/services/mac_manager/src/main/resources/application.properties +++ b/services/mac_manager/src/main/resources/application.properties @@ -6,6 +6,8 @@ spring.redis.host=redis2 # Please check redis pod service cluster IP #spring.redis.host=10.99.0.27 spring.redis.port=6379 +ignite.host=127.0.0.1 +ignite.port=47500 #apache.kafka.address=172.17.0.1:9092 #Logging configuration logging.level.root=info @@ -19,4 +21,6 @@ logging.type=file #ignite.key-store-password=123456 #ignite.trust-store-path=F:\\work\\alcor\\git\\chenpp\\alcor\\src\\resources\\truststore.jks #ignite.trust-store-password=123456 -macmanager.oui = 00-AA-BB \ No newline at end of file +macmanager.oui = 00-AA-BB +macmanager.pool.size = 100 +macmanager.retrylimit = 10 \ No newline at end of file diff --git a/services/mac_manager/src/test/java/com/futurewei/alcor/macmanager/AlcorMacManager/MacManagerApplicationTests.java b/services/mac_manager/src/test/java/com/futurewei/alcor/macmanager/AlcorMacManager/MacManagerApplicationTests.java index 93e792f2c..0b19ef50b 100644 --- a/services/mac_manager/src/test/java/com/futurewei/alcor/macmanager/AlcorMacManager/MacManagerApplicationTests.java +++ b/services/mac_manager/src/test/java/com/futurewei/alcor/macmanager/AlcorMacManager/MacManagerApplicationTests.java @@ -1,18 +1,14 @@ package com.futurewei.alcor.macmanager.AlcorMacManager; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.futurewei.alcor.macmanager.entity.MacState; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -21,44 +17,18 @@ @SpringBootTest class MacManagerApplicationTests { - @Autowired - public MockMvc mvc; + @Autowired + public MockMvc mvc; - @Test - void contextLoads() { - } + @Test + void contextLoads() { + } - @Test - public void test_index() throws Exception { - this.mvc.perform(get("/start.html")) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(content().string(containsString("MacManager"))); - } - -// @Test -// public void test_createMacState() throws Exception { -// MacState macState = new MacState("", "project1", "vpc1", "port1"); -// ObjectMapper objectMapper = new ObjectMapper(); -// String json = objectMapper.writeValueAsString(macState); -// this.mvc.perform(post("/macs") -// .contentType(MediaType.APPLICATION_JSON) -// .content(json)) -// .andExpect(status().isOk()) -// .andReturn(); -// } -// -// @Test -// public void test_getMacStateByMacAddress() throws Exception { -// this.mvc.perform(get("/macs/00-00-00-00-00-00")) -// .andDo(print()) -// .andExpect(status().isOk()); -// } -// -// @Test -// public void test_deleteMacStateByMacAddress() throws Exception { -// this.mvc.perform(get("/macs/00-00-00-00-00-00")) -// .andDo(print()) -// .andExpect(status().isOk()); -// } + @Test + public void test_index() throws Exception { + this.mvc.perform(get("/start.html")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("MacManager"))); + } } diff --git a/services/mac_manager/src/test/java/com/futurewei/alcor/macmanager/controller/MacControllerTest.java b/services/mac_manager/src/test/java/com/futurewei/alcor/macmanager/controller/MacControllerTest.java index e1e198b0d..6d0d0c9dc 100644 --- a/services/mac_manager/src/test/java/com/futurewei/alcor/macmanager/controller/MacControllerTest.java +++ b/services/mac_manager/src/test/java/com/futurewei/alcor/macmanager/controller/MacControllerTest.java @@ -32,11 +32,7 @@ import org.springframework.http.MediaType; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; - -import java.util.Hashtable; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; @@ -188,7 +184,7 @@ public void test_getMacRangeByMacRangeId() throws Exception { .andExpect(status().isOk()); } - public void test_getAllMacRanges(@PathVariable String rangeid) throws Exception{ + public void test_getAllMacRanges(@PathVariable String rangeid) throws Exception { MacRange macRange = new MacRange("range2", "00-AA-BB-11-22-22", "00-AA-BB-11-22-FF", "Active"); String strRangeId = createMacRange(macRange); macRange = new MacRange("range3", "00-AA-BB-11-33-33", "00-AA-BB-11-FF", "Active"); diff --git a/services/node_manager/.gitignore b/services/node_manager/.gitignore new file mode 100644 index 000000000..a2a3040aa --- /dev/null +++ b/services/node_manager/.gitignore @@ -0,0 +1,31 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/** +!**/src/test/** + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ diff --git a/services/node_manager/.mvn/wrapper/MavenWrapperDownloader.java b/services/node_manager/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 000000000..e76d1f324 --- /dev/null +++ b/services/node_manager/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,117 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/services/node_manager/.mvn/wrapper/maven-wrapper.jar b/services/node_manager/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 000000000..2cc7d4a55 Binary files /dev/null and b/services/node_manager/.mvn/wrapper/maven-wrapper.jar differ diff --git a/services/node_manager/.mvn/wrapper/maven-wrapper.properties b/services/node_manager/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 000000000..642d572ce --- /dev/null +++ b/services/node_manager/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/services/node_manager/mvnw b/services/node_manager/mvnw new file mode 100644 index 000000000..a16b5431b --- /dev/null +++ b/services/node_manager/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/services/node_manager/mvnw.cmd b/services/node_manager/mvnw.cmd new file mode 100644 index 000000000..c8d43372c --- /dev/null +++ b/services/node_manager/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/services/node_manager/pom.xml b/services/node_manager/pom.xml new file mode 100644 index 000000000..8cfdf4e50 --- /dev/null +++ b/services/node_manager/pom.xml @@ -0,0 +1,93 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.6.RELEASE + + + com.futurewei.alcor.nodemanager + AlcorNodeManager + 0.0.1-SNAPSHOT + AlcorNodeManager + Physical Node Manager Module + + + 1.8 + 2.8.0 + + + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-web + + + com.google.protobuf + protobuf-java + 3.8.0 + + + org.projectlombok + lombok + 1.18.0 + + + org.apache.commons + commons-pool2 + 2.4.2 + + + com.googlecode.json-simple + json-simple + 1.1.1 + + + org.apache.ignite + ignite-core + ${ignite.version} + + + org.apache.ignite + ignite-spring + ${ignite.version} + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + com.futurewei.alcor.common + AlcorCommonLib + 0.1.0-SNAPSHOT + compile + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/NodeManagerApplication.java b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/NodeManagerApplication.java new file mode 100644 index 000000000..5dcb575ca --- /dev/null +++ b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/NodeManagerApplication.java @@ -0,0 +1,12 @@ +package com.futurewei.alcor.nodemanager; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class NodeManagerApplication { + + public static void main(String[] args) { + SpringApplication.run(NodeManagerApplication.class, args); + } +} diff --git a/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/controller/NodeController.java b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/controller/NodeController.java new file mode 100644 index 000000000..4e0eabbaa --- /dev/null +++ b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/controller/NodeController.java @@ -0,0 +1,131 @@ +/*Copyright 2019 The Alcor Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +package com.futurewei.alcor.nodemanager.controller; + +import com.futurewei.alcor.common.exception.ParameterNullOrEmptyException; +import com.futurewei.alcor.common.exception.ResourcePersistenceException; +import com.futurewei.alcor.nodemanager.entity.NodeInfo; +import com.futurewei.alcor.nodemanager.entity.NodeInfoJson; +import com.futurewei.alcor.nodemanager.service.NodeService; +import com.futurewei.alcor.nodemanager.utils.RestPreconditionsUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; + +import static org.springframework.web.bind.annotation.RequestMethod.*; + +@RestController +public class NodeController { + + @Autowired + private NodeService service; + + @RequestMapping( + method = GET, + value = {"/nodes/{nodeid}", "/v4/nodes/{nodeid}"}) + public NodeInfoJson getNodeInfoByMacAddress(@PathVariable String nodeid) throws Exception { + NodeInfo hostInfo = null; + try { + RestPreconditionsUtil.verifyParameterNotNullorEmpty(nodeid); + hostInfo = service.getNodeInfoById(nodeid); + } catch (ParameterNullOrEmptyException e) { + //TODO: REST error code + throw new Exception(e); + } + + if (hostInfo == null) { + //TODO: REST error code + return new NodeInfoJson(); + } + return new NodeInfoJson(hostInfo); + } + + @RequestMapping( + method = GET, + value = {"/nodes", "/v4/nodes"}) + public List getAllNodes() throws Exception { + List nodes = null; + try { + nodes = service.getAllNodes(); + } catch (ParameterNullOrEmptyException e) { + //TODO: REST error code + throw new Exception(e); + } + if (nodes == null) { + //TODO: REST error code + return new ArrayList(); + } + return nodes; + } + + @RequestMapping( + method = POST, + value = {"/nodes", "/v4/nodes"}) + @ResponseStatus(HttpStatus.CREATED) + public NodeInfoJson createNodeInfo(@RequestBody NodeInfoJson resource) throws Exception { + NodeInfo hostInfo = null; + try { + NodeInfo inNodeInfo = resource.getNodeInfo(); + RestPreconditionsUtil.verifyParameterNotNullorEmpty(inNodeInfo); + hostInfo = service.createNodeInfo(inNodeInfo); + if (hostInfo == null) { + throw new ResourcePersistenceException(); + } + } catch (ParameterNullOrEmptyException e) { + throw new Exception(e); + } catch (Exception e) { + throw new Exception(e); + } + return new NodeInfoJson(hostInfo); + } + + @RequestMapping( + method = PUT, + value = {"/nodes/{nodeid}", "/v4/nodes/{nodeid}"}) + public NodeInfoJson updateNodeInfo(@PathVariable String nodeid, @RequestBody NodeInfoJson resource) throws Exception { + NodeInfo hostInfo = null; + try { + NodeInfo inNodeInfo = resource.getNodeInfo(); + RestPreconditionsUtil.verifyParameterNotNullorEmpty(inNodeInfo); + RestPreconditionsUtil.verifyParameterValid(nodeid, inNodeInfo); + hostInfo = service.updateNodeInfo(nodeid, inNodeInfo); + if (hostInfo == null) { + throw new ResourcePersistenceException(); + } + } catch (ParameterNullOrEmptyException e) { + throw new Exception(e); + } catch (Exception e) { + throw new Exception(e); + } + return new NodeInfoJson(hostInfo); + } + + @RequestMapping( + method = DELETE, + value = {"/nodes/{nodeid}", "/v4/nodes/{nodeid}"}) + public String deleteMacAllocation(@PathVariable String nodeid) throws Exception { + String macAddress = null; + try { + RestPreconditionsUtil.verifyParameterNotNullorEmpty(nodeid); + macAddress = service.deleteNodeInfo(nodeid); + } catch (ParameterNullOrEmptyException e) { + throw new Exception(e); + } + return "{Node(Node) Id: " + nodeid + "}"; + } +} diff --git a/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/dao/NodeRepository.java b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/dao/NodeRepository.java new file mode 100644 index 000000000..27641dcf9 --- /dev/null +++ b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/dao/NodeRepository.java @@ -0,0 +1,92 @@ +/*Copyright 2019 The Alcor Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +package com.futurewei.alcor.nodemanager.dao; + +import com.futurewei.alcor.common.db.CacheException; +import com.futurewei.alcor.common.db.CacheFactory; +import com.futurewei.alcor.common.db.ICache; +import com.futurewei.alcor.common.db.Transaction; +import com.futurewei.alcor.common.repo.ICacheRepository; +import com.futurewei.alcor.nodemanager.entity.NodeInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.stereotype.Repository; + +import javax.annotation.PostConstruct; +import java.util.Map; + +@Repository +@ComponentScan(value = "com.futurewei.alcor.common.db") +public class NodeRepository implements ICacheRepository { + private static final Logger logger = LoggerFactory.getLogger(NodeRepository.class); + private ICache cache; + + @Autowired + public NodeRepository(CacheFactory cacheFactory) { + cache = cacheFactory.getCache(NodeInfo.class); + } + + public ICache getCache() { + return cache; + } + + @PostConstruct + private void init() { + logger.info("NodeRepository init completed"); + } + + @Override + public NodeInfo findItem(String id) throws CacheException { + return cache.get(id); + } + + @Override + public Map findAllItems() throws CacheException { + return cache.getAll(); + } + + @Override + public void addItem(NodeInfo nodeInfo) throws CacheException { + logger.info("Add node, Node Id:" + nodeInfo.getId()); + cache.put(nodeInfo.getId(), nodeInfo); + } + + @Override + public void deleteItem(String id) throws CacheException { + logger.info("Delete node, Node Id:" + id); + cache.remove(id); + } + + /** + * add a new node info to node repository + * @param nodeInfo new node information + * @return void + * @throws Exception Db or cache operation exception + */ + public void addItemTransaction(NodeInfo nodeInfo) throws Exception { + logger.info("Add node, Node Id:" + nodeInfo.getId()); + cache.put(nodeInfo.getId(), nodeInfo); + String ipAddr; + + try (Transaction tx = cache.getTransaction().start()) { + cache.put(nodeInfo.getId(), nodeInfo); + tx.commit(); + } catch (Exception e) { + throw e; + } + } +} diff --git a/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/entity/NodeInfo.java b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/entity/NodeInfo.java new file mode 100644 index 000000000..df433d68b --- /dev/null +++ b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/entity/NodeInfo.java @@ -0,0 +1,99 @@ +/*Copyright 2019 The Alcor Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +package com.futurewei.alcor.nodemanager.entity; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.futurewei.alcor.nodemanager.utils.NodeUtil; +import lombok.Data; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.Serializable; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@Data +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, + setterVisibility = JsonAutoDetect.Visibility.NONE, creatorVisibility = JsonAutoDetect.Visibility.NONE) +public class NodeInfo implements Serializable { + private static final Logger logger = LoggerFactory.getLogger(NodeInfo.class); + + @JsonProperty("node_id") + private String id; + + @JsonProperty("node_name") + private String name; + + @JsonProperty("local_ip") + private InetAddress localIp; + + @JsonProperty("mac_address") + private String macAddress; + + @JsonProperty("veth") + private String veth; + + @JsonProperty("server_port") + private int gRPCServerPort; + + public NodeInfo() { + + } + + public NodeInfo(NodeInfo nodeInfo) { + this(nodeInfo.id, nodeInfo.name, nodeInfo.localIp, nodeInfo.macAddress, nodeInfo.veth, nodeInfo.gRPCServerPort); + } + + public NodeInfo(String id, String name, InetAddress localIp, String macAddress, String veth, int gRPCServerPort) { + this.id = id; + this.name = name; + this.localIp = localIp; + this.macAddress = macAddress; + this.veth = veth; + this.gRPCServerPort = gRPCServerPort; + } + + public NodeInfo(String nodeId, String nodeName, byte[] ipAddress, String macAddress, int gRPCServerPort) { + this(nodeId, nodeName, ipAddress, macAddress); + this.veth = ""; + this.gRPCServerPort = gRPCServerPort; + } + + public NodeInfo(String nodeId, String nodeName, byte[] ipAddress, String macAddress) { + this.id = nodeId; + this.name = nodeName; + try { + this.localIp = InetAddress.getByAddress(ipAddress); + if (this.validate(macAddress)) { + this.macAddress = macAddress; + } else { + this.macAddress = ""; + } + } catch (UnknownHostException e) { + logger.error(NodeUtil.NODE_EXCEPTION_NODE_IP_INVALID + ipAddress, e); + } + this.veth = ""; + this.gRPCServerPort = NodeUtil.GRPC_SERVER_PORT; + } + + private boolean validate(String mac) { + Pattern p = Pattern.compile("^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$"); + Matcher m = p.matcher(mac); + return m.find(); + } +} diff --git a/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/entity/NodeInfoJson.java b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/entity/NodeInfoJson.java new file mode 100644 index 000000000..284e88f2b --- /dev/null +++ b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/entity/NodeInfoJson.java @@ -0,0 +1,41 @@ +/*Copyright 2019 The Alcor Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +package com.futurewei.alcor.nodemanager.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class NodeInfoJson { + + @JsonProperty("host_info") + private NodeInfo nodeInfo; + + public NodeInfoJson() { + + } + + public NodeInfoJson(NodeInfo nodeInfo) { + this.nodeInfo = nodeInfo; + } + + public NodeInfo getNodeInfo() { + return nodeInfo; + } + + public void setNodeInfo(NodeInfo nodeInfo) { + this.nodeInfo = nodeInfo; + } +} diff --git a/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/service/NodeService.java b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/service/NodeService.java new file mode 100644 index 000000000..e0ddf906f --- /dev/null +++ b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/service/NodeService.java @@ -0,0 +1,18 @@ +package com.futurewei.alcor.nodemanager.service; + +import com.futurewei.alcor.nodemanager.entity.NodeInfo; + +import java.util.Hashtable; +import java.util.List; + +public interface NodeService { + NodeInfo getNodeInfoById(String nodeId) throws Exception; + + List getAllNodes() throws Exception; + + NodeInfo createNodeInfo(NodeInfo nodeInfo) throws Exception; + + NodeInfo updateNodeInfo(String nodeId, NodeInfo nodeInfo) throws Exception; + + String deleteNodeInfo(String nodeId) throws Exception; +} diff --git a/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/service/datacenter/DataCenterConfig.java b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/service/datacenter/DataCenterConfig.java new file mode 100644 index 000000000..fec1ed2d3 --- /dev/null +++ b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/service/datacenter/DataCenterConfig.java @@ -0,0 +1,20 @@ +/* +Copyright 2019 The Alcor Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +package com.futurewei.alcor.nodemanager.service.datacenter; + +public class DataCenterConfig { + +} diff --git a/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/service/datacenter/DataCenterConfigLoader.java b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/service/datacenter/DataCenterConfigLoader.java new file mode 100644 index 000000000..91c1509f6 --- /dev/null +++ b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/service/datacenter/DataCenterConfigLoader.java @@ -0,0 +1,112 @@ +/* +Copyright 2019 The Alcor Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package com.futurewei.alcor.nodemanager.service.datacenter; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.futurewei.alcor.nodemanager.entity.NodeInfo; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.ResourceLoader; +import org.springframework.stereotype.Component; + +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +@Component +public class DataCenterConfigLoader { + private static final Logger logger = LoggerFactory.getLogger(DataCenterConfigLoader.class); + + @Autowired + private ResourceLoader resourceLoader; + + @Value("${alcor.machine.config:.\\machine.json}") + private String machineConfigFile; + + //String getPropertyFile() { + // return resourceLoader.getResource(this.machineConfigFile).getFilename(); + //} + + public List loadAndGetHostNodeList() { + logger.info("Loading node from " + this.machineConfigFile); + return this.loadAndGetHostNodeList(this.machineConfigFile); + } + + @JsonIgnore + public List loadAndGetHostNodeList(String machineConfigFilePath) { + JSONParser jsonParser = new JSONParser(); + List nodeInfos = new ArrayList<>(); + logger.info(this.getClass().getName(), "loadAndGetHostNodeList(String machineConfigFilePath)"); + try (FileReader reader = new FileReader(machineConfigFilePath)) { + JSONObject obj = (JSONObject) jsonParser.parse(reader); + JSONArray nodeList = (JSONArray) obj.get("Hosts"); + + nodeList.forEach(node -> { + NodeInfo hostNode = this.parseNodeObject((JSONObject) node); + if (hostNode != null) nodeInfos.add(hostNode); + }); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } + return nodeInfos; + } + + @JsonIgnore + private NodeInfo parseNodeObject(JSONObject node) { + String id = (String) node.get("id"); + String ip = (String) node.get("ip"); + String mac = (String) node.get("mac"); + byte[] ipByteArray; + try { + ipByteArray = fromIpAddressStringToByteArray(ip); + return new NodeInfo(id, id, ipByteArray, mac); + } catch (UnknownHostException e) { + logger.error("UnknownHostException"); + } + return null; + } + + @JsonIgnore + public byte[] fromIpAddressStringToByteArray(String ipAddressString) throws UnknownHostException { + InetAddress ip = InetAddress.getByName(ipAddressString); + byte[] bytes = ip.getAddress(); + return bytes; + } + + public int getRandomNumberInRange(int min, int max) { + if (min >= max) { + throw new IllegalArgumentException("Max must be greater than min"); + } + Random r = new Random(); + return r.nextInt((max - min) + 1) + min; + } +} diff --git a/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/service/datacenter/NodeManager.java b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/service/datacenter/NodeManager.java new file mode 100644 index 000000000..a19112aba --- /dev/null +++ b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/service/datacenter/NodeManager.java @@ -0,0 +1,123 @@ +/*Copyright 2019 The Alcor Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +package com.futurewei.alcor.nodemanager.service.datacenter; + +//import com.futurewei.alcor.controller.utilities.Common; + +import com.futurewei.alcor.nodemanager.entity.NodeInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Hashtable; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +@Component +public class NodeManager { + private static final Logger logger = LoggerFactory.getLogger(NodeManager.class); + + @Autowired + public DataCenterConfigLoader dataCenterConfigLoader; + + //private List nodes; + private Hashtable nodeTable; + + public NodeManager() { + nodeTable = null; + } + + public NodeManager(List nodes) { + nodeTable = null; + for (NodeInfo node : nodes) { + logger.info("Log:" + node); + } + this.BuildTableFromNodeIdToInfo(nodes); + } + + private List LoadNodes() { + if (nodeTable == null) { + List nodes = dataCenterConfigLoader.loadAndGetHostNodeList(); + BuildTableFromNodeIdToInfo(nodes); + } + return new ArrayList(nodeTable.values()); + } + + public NodeInfo getNodeInfoById(String nodeId) { + LoadNodes(); + if (this.nodeTable != null) { + return this.nodeTable.get(nodeId); + } else + return null; + } + + public Hashtable getAllNodes() { + LoadNodes(); + return this.nodeTable; + } + + public List getAllNodesList() { + LoadNodes(); + return new ArrayList(nodeTable.values()); + } + + public Collection getAllNodes2() { + LoadNodes(); + if (this.nodeTable != null) { + return this.nodeTable.values(); + } else + return null; + } + + public NodeInfo[] getRandomHosts(int count) { + LoadNodes(); + NodeInfo[] randomHosts = new NodeInfo[count]; + for (int i = 0; i < count; i++) { + int index = ThreadLocalRandom.current().nextInt(0, this.getAllNodes().size() - 1); + randomHosts[i] = this.getAllNodes().get(index); + } + return randomHosts; + } + + public void putNode(NodeInfo nodeInfo) { + LoadNodes(); + if (this.nodeTable != null) { + logger.info("Log:" + "[NodeManager] Add Host id: " + nodeInfo.getId()); + this.nodeTable.put(nodeInfo.getId(), nodeInfo); + } + } + + public String deleteNode(String nodeId) { + LoadNodes(); + if (this.nodeTable != null) { + logger.info("Log:" + "[NodeManager] Delete Host id: " + nodeId); + this.nodeTable.remove(nodeId); + } + return nodeId; + } + + private void BuildTableFromNodeIdToInfo(List nodes) { + nodeTable = new Hashtable(); + if (nodes != null) { + logger.info("nodes size : " + nodes.size()); + for (NodeInfo node : nodes) { + this.nodeTable.put(node.getId(), node); + } + } + } +} diff --git a/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/service/implement/NodeServiceImpl.java b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/service/implement/NodeServiceImpl.java new file mode 100644 index 000000000..c17c093ba --- /dev/null +++ b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/service/implement/NodeServiceImpl.java @@ -0,0 +1,171 @@ +/*Copyright 2019 The Alcor Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +package com.futurewei.alcor.nodemanager.service.implement; + +import com.futurewei.alcor.common.exception.ParameterNullOrEmptyException; +import com.futurewei.alcor.nodemanager.dao.NodeRepository; +import com.futurewei.alcor.nodemanager.entity.NodeInfo; +import com.futurewei.alcor.nodemanager.service.NodeService; +import com.futurewei.alcor.nodemanager.service.datacenter.NodeManager; +import com.futurewei.alcor.nodemanager.utils.NodeUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; + +@Service +public class NodeServiceImpl implements NodeService { + private static final Logger logger = LoggerFactory.getLogger(NodeServiceImpl.class); + public Hashtable Nodes = new Hashtable(); + + @Value("${nodemanager.nodeinfo.location}") + private int nodeInfoLocation; + + @Autowired + private NodeRepository nodeRepository; + + @Autowired + private NodeManager nodeManager; + + @Override + public NodeInfo getNodeInfoById(String nodeId) throws Exception { + if (nodeId == null) + throw (new ParameterNullOrEmptyException(NodeUtil.NODE_EXCEPTION_PARAMETER_NULL_EMPTY)); + NodeInfo nodeInfo = null; + try { + switch (nodeInfoLocation) { + case NodeUtil.NODE_INFO_FILE: { + nodeInfo = nodeManager.getNodeInfoById(nodeId); + break; + } + case NodeUtil.NODE_INFO_REPOSITOTY: { + nodeInfo = nodeRepository.findItem(nodeId); + break; + } + } + } catch (Exception e) { + throw e; + } + return nodeInfo; + } + + @Override + public List getAllNodes() throws Exception { + List nodes = new ArrayList(); + try { + switch (nodeInfoLocation) { + case NodeUtil.NODE_INFO_FILE: { + nodes = nodeManager.getAllNodesList(); + break; + } + case NodeUtil.NODE_INFO_REPOSITOTY: { + nodes = new ArrayList(nodeRepository.findAllItems().values()); + break; + } + } + } catch (Exception e) { + throw e; + } + return nodes; + } + + @Override + public NodeInfo createNodeInfo(NodeInfo nodeInfo) throws Exception { + if (nodeInfo == null) + throw (new ParameterNullOrEmptyException(NodeUtil.NODE_EXCEPTION_PARAMETER_NULL_EMPTY)); + NodeInfo node = getNodeInfoById(nodeInfo.getId()); + if (node != null) { + if (nodeInfo.getId().equals(node.getId())) + throw (new ParameterNullOrEmptyException(NodeUtil.NODE_EXCEPTION_NODE_ALREADY_EXISTING)); + } + if (nodeInfo != null) { + try { + switch (nodeInfoLocation) { + case NodeUtil.NODE_INFO_FILE: { + nodeManager.putNode(nodeInfo); + break; + } + case NodeUtil.NODE_INFO_REPOSITOTY: { + nodeRepository.addItem(nodeInfo); + break; + } + } + } catch (Exception e) { + throw e; + } + } + return nodeInfo; + } + + @Override + public NodeInfo updateNodeInfo(String nodeId, NodeInfo nodeInfo) throws Exception { + if (nodeId == null || nodeInfo == null) + throw (new ParameterNullOrEmptyException(NodeUtil.NODE_EXCEPTION_PARAMETER_NULL_EMPTY)); + NodeInfo node = getNodeInfoById(nodeId); + if (node == null) + throw (new ParameterNullOrEmptyException(NodeUtil.NODE_EXCEPTION_NODE_NOT_EXISTING)); + else if (nodeId.equals(node.getId()) == false) { + throw (new ParameterNullOrEmptyException(NodeUtil.NODE_EXCEPTION_NODE_NOT_EXISTING)); + } + if (nodeInfo != null) { + try { + switch (nodeInfoLocation) { + case NodeUtil.NODE_INFO_FILE: { + nodeManager.putNode(nodeInfo); + break; + } + case NodeUtil.NODE_INFO_REPOSITOTY: { + nodeRepository.addItem(nodeInfo); + break; + } + } + } catch (Exception e) { + throw e; + } + } + return nodeInfo; + } + + @Override + public String deleteNodeInfo(String nodeId) throws Exception { + if (nodeId == null) + throw (new ParameterNullOrEmptyException(NodeUtil.NODE_EXCEPTION_PARAMETER_NULL_EMPTY)); + NodeInfo node = getNodeInfoById(nodeId); + if (node == null) + throw (new ParameterNullOrEmptyException(NodeUtil.NODE_EXCEPTION_NODE_NOT_EXISTING)); + else if (nodeId.equals(node.getId()) == false) + throw (new ParameterNullOrEmptyException(NodeUtil.NODE_EXCEPTION_NODE_NOT_EXISTING)); + try { + switch (nodeInfoLocation) { + case NodeUtil.NODE_INFO_FILE: { + nodeManager.deleteNode(nodeId); + break; + } + case NodeUtil.NODE_INFO_REPOSITOTY: { + nodeRepository.deleteItem(nodeId); + break; + } + } + } catch (Exception e) { + throw e; + } + return nodeId; + } +} diff --git a/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/utils/NodeUtil.java b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/utils/NodeUtil.java new file mode 100644 index 000000000..0935e0072 --- /dev/null +++ b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/utils/NodeUtil.java @@ -0,0 +1,27 @@ +/*Copyright 2019 The Alcor Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +package com.futurewei.alcor.nodemanager.utils; + +public class NodeUtil { + public static final int NODE_INFO_FILE = 1; + public static final int NODE_INFO_REPOSITOTY = 2; + public static final int GRPC_SERVER_PORT = 50001; + + //Exception Messages + public static final String NODE_EXCEPTION_PARAMETER_NULL_EMPTY = "Parameter is null or empty"; + public static final String NODE_EXCEPTION_NODE_IP_INVALID = "Invalid ip address"; + public static final String NODE_EXCEPTION_NODE_NOT_EXISTING = "The node to update or delete is not existing."; + public static final String NODE_EXCEPTION_NODE_ALREADY_EXISTING = "The node to create is already existing."; +} diff --git a/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/utils/RestPreconditionsUtil.java b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/utils/RestPreconditionsUtil.java new file mode 100644 index 000000000..c3e33914c --- /dev/null +++ b/services/node_manager/src/main/java/com/futurewei/alcor/nodemanager/utils/RestPreconditionsUtil.java @@ -0,0 +1,42 @@ +/* +Copyright 2019 The Alcor Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package com.futurewei.alcor.nodemanager.utils; + +import com.futurewei.alcor.common.exception.ParameterNullOrEmptyException; +import com.futurewei.alcor.common.exception.ParameterUnexpectedValueException; +import com.futurewei.alcor.nodemanager.entity.NodeInfo; +import org.thymeleaf.util.StringUtils; + +public class RestPreconditionsUtil { + public static void verifyParameterNotNullorEmpty(String resourceId) throws ParameterNullOrEmptyException { + if (StringUtils.isEmpty(resourceId)) { + throw new ParameterNullOrEmptyException("Empty parameter"); + } + } + + public static void verifyParameterNotNullorEmpty(NodeInfo resource) throws ParameterNullOrEmptyException { + if (resource == null) { + throw new ParameterNullOrEmptyException("null parameter"); + } + } + + public static void verifyParameterValid(String id, NodeInfo resource) throws ParameterUnexpectedValueException { + if (id.equals(resource.getId()) == false) { + throw new ParameterUnexpectedValueException("parameter values are not valid: parameter id and request body resource id should be same."); + } + } +} \ No newline at end of file diff --git a/services/node_manager/src/main/resources/application.properties b/services/node_manager/src/main/resources/application.properties new file mode 100644 index 000000000..f5a368243 --- /dev/null +++ b/services/node_manager/src/main/resources/application.properties @@ -0,0 +1,10 @@ +#ignite configuration +ignite.host=localhost +ignite.port=10800 +ignite.key-store-path=keystore.jks +ignite.key-store-password=123456 +ignite.trust-store-path=truststore.jks +ignite.trust-store-password=123456 +#1: machine.json file, 2:ignite +nodemanager.nodeinfo.location=1 +alcor.machine.config=D:\\dev\\alcor\\config\\machine.json diff --git a/services/node_manager/src/main/resources/static/start.html b/services/node_manager/src/main/resources/static/start.html new file mode 100644 index 000000000..0f03fb878 --- /dev/null +++ b/services/node_manager/src/main/resources/static/start.html @@ -0,0 +1,10 @@ + + + + + Start + + +Node Manager Module is running + + \ No newline at end of file diff --git a/services/node_manager/src/test/java/com/futurewei/alcor/nodemanager/AlcorNodeManager/NodeManagerApplicationTests.java b/services/node_manager/src/test/java/com/futurewei/alcor/nodemanager/AlcorNodeManager/NodeManagerApplicationTests.java new file mode 100644 index 000000000..575c9add4 --- /dev/null +++ b/services/node_manager/src/test/java/com/futurewei/alcor/nodemanager/AlcorNodeManager/NodeManagerApplicationTests.java @@ -0,0 +1,36 @@ +package com.futurewei.alcor.nodemanager.AlcorNodeManager; + +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import static org.hamcrest.Matchers.containsString; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest +@RunWith(SpringRunner.class) +@AutoConfigureMockMvc +class NodeManagerApplicationTests { + + @Autowired + public MockMvc mvc; + + @Test + void contextLoads() { + } + + @Test + public void test_index() throws Exception { + this.mvc.perform(get("/start.html")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("Node Manager"))); + } +} diff --git a/services/node_manager/src/test/java/com/futurewei/alcor/nodemanager/controller/NodeControllerTest.java b/services/node_manager/src/test/java/com/futurewei/alcor/nodemanager/controller/NodeControllerTest.java new file mode 100644 index 000000000..591c42837 --- /dev/null +++ b/services/node_manager/src/test/java/com/futurewei/alcor/nodemanager/controller/NodeControllerTest.java @@ -0,0 +1,156 @@ +/*Copyright 2019 The Alcor Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +package com.futurewei.alcor.nodemanager.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.futurewei.alcor.nodemanager.controller.NodeController; +import com.futurewei.alcor.nodemanager.entity.NodeInfo; +import com.futurewei.alcor.nodemanager.entity.NodeInfoJson; +import com.futurewei.alcor.nodemanager.service.NodeService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.bind.annotation.PathVariable; + +import java.net.InetAddress; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureMockMvc +public class NodeControllerTest { + private static final ObjectMapper om = new ObjectMapper(); + public NodeInfo testNodeInfo; + String strTestNodeId = ""; + + @Autowired + NodeService service; + + @Autowired + private MockMvc mockMvc; + + @MockBean + private NodeController mockController; + + @Before + public void init() { + byte[] ip = new byte[]{10,0,0,1}; + NodeInfo nodeInfo = new NodeInfo("h00", "host0", ip, "AA-BB-CC-DD-EE-00"); + NodeInfoJson nodeInfoJson = new NodeInfoJson(nodeInfo); + ObjectMapper objectMapper = new ObjectMapper(); + + try { + String json = objectMapper.writeValueAsString(nodeInfoJson); + NodeInfo nodeInfo2 = service.createNodeInfo(nodeInfo); + strTestNodeId = nodeInfo2.getId(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public String createNodeInfo(NodeInfo nodeInfo) { + NodeInfoJson nodeInfoJson = new NodeInfoJson(nodeInfo); + ObjectMapper objectMapper = new ObjectMapper(); + String strNodeId = ""; + try { + String json = objectMapper.writeValueAsString(nodeInfoJson); + NodeInfo nodeInfo2 = service.createNodeInfo(nodeInfo); + strTestNodeId = nodeInfo2.getId(); + } catch (Exception e) { + e.printStackTrace(); + } + return strTestNodeId; + } + + @Test + public void test_index() throws Exception { + this.mockMvc.perform(get("/start.html")) + .andDo(print()) + .andExpect(status().isOk()); + } + + @Test + public void test_createNodeInfo() throws Exception { + byte[] ip = new byte[]{10,0,0,1}; + NodeInfo nodeInfo = new NodeInfo("h01", "host1", ip, "AA-BB-CC-DD-EE-11"); + NodeInfoJson nodeInfoJson = new NodeInfoJson(nodeInfo); + ObjectMapper objectMapper = new ObjectMapper(); + String json = objectMapper.writeValueAsString(nodeInfoJson); + + this.mockMvc.perform(post("/nodes") + .content(json) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)) + .andExpect(status().isCreated()) + .andDo(print()); + } + + @Test + public void updateNodeInfo() throws Exception { + InetAddress address2 = InetAddress.getByName("10.0.0.2"); + byte[] ip = new byte[]{10,0,0,2}; + NodeInfo nodeInfo = new NodeInfo("h02", "host2", ip, "AA-BB-CC-DD-EE-22"); + NodeInfoJson nodeInfoJson = new NodeInfoJson(nodeInfo); + ObjectMapper objectMapper = new ObjectMapper(); + String json = objectMapper.writeValueAsString(nodeInfoJson); + + this.mockMvc.perform(put("/nodes/h01") + .content(json) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andDo(print()); + } + + @Test + public void test_getNodeInfoByNodeId() throws Exception { + byte[] ip = new byte[]{10,0,0,3}; + NodeInfo nodeInfo = new NodeInfo("h03", "host3", ip, "AA-BB-CC-03-03-03"); + String strNodeId = createNodeInfo(nodeInfo); + this.mockMvc.perform(get("/nodes/" + strNodeId)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @Test + public void test_getAllNodes() throws Exception { + byte[] ip1 = new byte[]{10,0,0,4}; + NodeInfo nodeInfo1 = new NodeInfo("h04", "host4", ip1, "AA-BB-CC-04-04-04"); + createNodeInfo(nodeInfo1); + byte[] ip2 = new byte[]{10,0,0,5}; + NodeInfo nodeInfo2 = new NodeInfo("h05", "host5", ip2, "AA-BB-CC-05-05-05"); + createNodeInfo(nodeInfo2); + this.mockMvc.perform(get("/nodes")) + .andDo(print()) + .andExpect(status().isOk()); + } + + @Test + public void deleteNodeInfo() throws Exception { + String strNodeId = "h00"; + this.mockMvc.perform(delete("/nodes/" + strNodeId)) + .andDo(print()) + .andExpect(status().isOk()); + } +} \ No newline at end of file