Skip to content

Commit

Permalink
Refactor/ai node build update (#13349)
Browse files Browse the repository at this point in the history
* Refactor/ai node build update (#13302)

* fix: Hopefully fixed the build of the cpp-example on windows systems

* fix: Increase the timeout even more to finally make the build succeed.

* fix: Fix the build.

* refactor: Cleaned up the build of the ai-node to be more robust

* fix: Made the groovy script also work when building the entire project.

* feat: Added some checks to validate the min and max version of the python3 version being used.

* feat: Added some checks to validate the min and max version of the python3 version being used.

* fix: Updated the python settings in pyproject.toml to reflect the really valid range of python versions and updated the prerequisite check accordingly.

* feat: Removed the option to remove an AI node by rpc-ip+port.

* chore: Added the poetry.lock to the .gitignore

* docs: Removed the option to use the ip+port from the output of the scripts.

* chore: Added the poetry.lock to the repo and removed it from the .gitignore file

(cherry picked from commit 7c808c5)

* set ainode version

---------

Co-authored-by: Christofer Dutz <[email protected]>
  • Loading branch information
ycycse and chrisdutz authored Aug 29, 2024
1 parent 8ed0603 commit bde8d66
Show file tree
Hide file tree
Showing 9 changed files with 1,882 additions and 208 deletions.
52 changes: 20 additions & 32 deletions iotdb-core/ainode/iotdb/ainode/script.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,45 +47,30 @@ def main():
elif command == 'remove':
try:
logger.info("Removing AINode...")
if len(arguments) >= 3:
target_ainode = arguments[2]
# parameter pattern: <ainode-id> or <ip>:<rpc-port>
ainode_info = target_ainode.split(POINT_COLON)
target_ainode_id = -1
# Delete the current node
if len(arguments) == 2:
target_ainode_id = descriptor.get_config().get_ainode_id()
target_rpc_address = descriptor.get_config().get_ain_inference_rpc_address()
target_rpc_port = descriptor.get_config().get_ain_inference_rpc_port()

# ainode id
if len(ainode_info) == 1:
target_ainode_id = int(ainode_info[0])
# Delete the node with a given id
elif len(arguments) == 3:
target_ainode_id = arguments[2]

ainode_configuration_map = client_manager.borrow_config_node_client().get_ainode_configuration(
target_ainode_id)
# ainode id
ainode_configuration_map = client_manager.borrow_config_node_client().get_ainode_configuration(target_ainode_id)

end_point = ainode_configuration_map[target_ainode_id].location.internalEndPoint
target_rpc_address = end_point.ip
target_rpc_port = end_point.port
elif len(ainode_info) == 2:
target_rpc_address = ainode_info[0]
target_rpc_port = int(ainode_info[1])
end_point = ainode_configuration_map[target_ainode_id].location.internalEndPoint
target_rpc_address = end_point.ip
target_rpc_port = end_point.port

ainode_configuration_map = client_manager.borrow_config_node_client().get_ainode_configuration(-1)
if not end_point:
raise MissingConfigError("NodeId: {} not found in cluster ".format(target_ainode_id))

for cur_ainode_id, cur_configuration in ainode_configuration_map.items():
cur_end_point = cur_configuration.location.internalEndPoint
if cur_end_point.ip == target_rpc_address and cur_end_point.port == target_rpc_port:
target_ainode_id = cur_ainode_id
break
if target_ainode_id == -1:
raise MissingConfigError(
"Can't find ainode through {}:{}".format(target_rpc_port, target_rpc_address))
else:
raise MissingConfigError("NodeId or IP:Port should be provided to remove AINode")
logger.info('Got target AINode id: {}'.format(target_ainode_id))

logger.info('Got target AINode id: {}, address: {}, port: {}'
.format(target_ainode_id, target_rpc_address, target_rpc_port))
else:
target_ainode_id = descriptor.get_config().get_ainode_id()
target_rpc_address = descriptor.get_config().get_ain_inference_rpc_address()
target_rpc_port = descriptor.get_config().get_ain_inference_rpc_port()
raise MissingConfigError("Invalid command")

location = TAINodeLocation(target_ainode_id, TEndPoint(target_rpc_address, target_rpc_port))
status = client_manager.borrow_config_node_client().node_remove(location)
Expand All @@ -100,3 +85,6 @@ def main():
sys.exit(1)
else:
logger.warning("Unknown argument: {}.".format(command))

if __name__ == '__main__':
main()
1,442 changes: 1,442 additions & 0 deletions iotdb-core/ainode/poetry.lock

Large diffs are not rendered by default.

357 changes: 190 additions & 167 deletions iotdb-core/ainode/pom.xml

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions iotdb-core/ainode/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "apache-iotdb-ainode"
version = "1.4.0.dev"
version = "1.3.3.dev"
description = "Apache IoTDB AINode"
readme = "README.md"
authors = ["Apache Software Foundation <[email protected]>"]
Expand All @@ -46,7 +46,7 @@ packages = [
]

[tool.poetry.dependencies]
python = "^3.8"
python = ">=3.8, <3.13"

numpy = "^1.21.4"
pandas = "^1.3.5"
Expand Down
21 changes: 21 additions & 0 deletions iotdb-core/ainode/resources/pom.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#
# 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
#
# 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.

artifactId=iotdb-ainode
groupId=org.apache.iotdb
version=${project.version}
4 changes: 1 addition & 3 deletions iotdb-core/ainode/resources/sbin/remove-ainode.bat
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@ IF "%~1"=="--help" (
echo Usage:
echo Remove the AINode with ainode_id
echo ./sbin/remove-ainode.bat -t [ainode_id]
echo Remove the AINode with address:port
echo ./sbin/remove-ainode.bat -t [ain_inference_rpc_address:ain_inference_rpc_port]
echo.
echo Options:
echo ^ ^ -t = ainode_id or [ain_inference_rpc_address:ain_inference_rpc_port]
echo ^ ^ -t = ainode_id
echo ^ ^ -i = When specifying the Python interpreter please enter the address of the executable file of the Python interpreter in the virtual environment. Currently AINode supports virtual environments such as venv, conda, etc. Inputting the system Python interpreter as the installation location is not supported. In order to ensure that scripts are recognized properly, please use absolute paths whenever possible!
EXIT /B 0
)
Expand Down
4 changes: 1 addition & 3 deletions iotdb-core/ainode/resources/sbin/remove-ainode.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,9 @@ if [ "$#" -eq 1 ] && [ "$1" == "--help" ]; then
echo "Usage:"
echo "Remove the AINode with ainode_id"
echo "./sbin/remove-ainode.sh -t [ainode_id]"
echo "Remove the AINode with address:port"
echo "./sbin/remove-ainode.sh -t [ain_inference_rpc_address:ain_inference_rpc_port]"
echo ""
echo "Options:"
echo " -t = ainode_id or [ain_inference_rpc_address:ain_inference_rpc_port]"
echo " -t = ainode_id"
echo " -i = When specifying the Python interpreter please enter the address of the executable file of the Python interpreter in the virtual environment. Currently AINode supports virtual environments such as venv, conda, etc. Inputting the system Python interpreter as the installation location is not supported. In order to ensure that scripts are recognized properly, please use absolute paths whenever possible!"
exit 0
fi
Expand Down
192 changes: 192 additions & 0 deletions iotdb-core/ainode/resources/syncPythonVersion.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/*
* 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
*
* 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.
*/

import groovy.toml.TomlSlurper

import java.util.regex.Matcher

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// The entire Python "check" block is borrowed from Apache PLC4X's build.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

allConditionsMet = true

/**
* Version extraction function/macro. It looks for occurrence of x.y or x.y.z
* in passed input text (likely output from `program --version` command if found).
*
* @param input
* @return
*/
private static Matcher extractVersion(input) {
def matcher = input =~ /(\d+\.\d+(\.\d+)?).*/
matcher
}

def checkVersionAtLeast(String current, String minimum) {
def currentSegments = current.tokenize('.')
def minimumSegments = minimum.tokenize('.')
def numSegments = Math.min(currentSegments.size(), minimumSegments.size())
for (int i = 0; i < numSegments; ++i) {
def currentSegment = currentSegments[i].toInteger()
def minimumSegment = minimumSegments[i].toInteger()
if (currentSegment < minimumSegment) {
println current.padRight(14) + " FAILED (required min " + minimum + " but got " + current + ")"
return false
} else if (currentSegment > minimumSegment) {
println current.padRight(14) + " OK"
return true
}
}
def curNotShorter = currentSegments.size() >= minimumSegments.size()
if (curNotShorter) {
println current.padRight(14) + " OK"
} else {
println current.padRight(14) + " (required min " + minimum + " but got " + current + ")"
}
curNotShorter
}

def checkVersionAtMost(String current, String maximum) {
def currentSegments = current.tokenize('.')
def maximumSegments = maximum.tokenize('.')
def numSegments = Math.min(currentSegments.size(), maximumSegments.size())
for (int i = 0; i < numSegments; ++i) {
def currentSegment = currentSegments[i].toInteger()
def maximumSegment = maximumSegments[i].toInteger()
if (currentSegment > maximumSegment) {
println current.padRight(14) + " FAILED (required max " + maximum + " but got " + current + ")"
return false
} else if (currentSegment < maximumSegment) {
println current.padRight(14) + " OK"
return true
}
}
def curNotShorter = currentSegments.size() >= maximumSegments.size()
if (curNotShorter) {
println current.padRight(14) + " OK"
} else {
println current.padRight(14) + " (required max " + maximum + " but got " + current + ")"
}
curNotShorter
}

def checkPython() {
String python = project.properties['python.exe.bin']
println "Using python executable: " + python.padRight(14) + " OK"
print "Detecting Python version: "
try {
def process = (python + " --version").execute()
def stdOut = new StringBuilder()
def stdErr = new StringBuilder()
process.waitForProcessOutput(stdOut, stdErr)
Matcher matcher = extractVersion(stdOut + stdErr)
if (matcher.size() > 0) {
String curVersion = matcher[0][1]
def result = checkVersionAtLeast(curVersion, "3.8.0")
if (!result) {
allConditionsMet = false
}
result = checkVersionAtMost(curVersion, "3.13")
if (!result) {
allConditionsMet = false
}
} else {
println "missing (Please install at least version 3.8.0 and at most one of the 3.13.x versions)"
allConditionsMet = false
}
} catch (Exception ignored) {
println "missing"
println "--- output of version `${python} --version` command ---"
println output
println "----------------------------------------------------"
allConditionsMet = false
}
}


// On Ubuntu it seems that venv is generally available, but the 'ensurepip' command fails.
// In this case we need to install the python3-venv package. Unfortunately checking the
// venv is successful in this case, so we need this slightly odd test.
def checkPythonVenv() {
print "Detecting venv: "
try {
def python = project.properties['python.exe.bin']
def cmdArray = [python, "-Im", "ensurepip"]
def process = cmdArray.execute()
def stdOut = new StringBuilder()
def stdErr = new StringBuilder()
process.waitForProcessOutput(stdOut, stdErr)
if (stdErr.contains("No module named")) {
println "missing"
println "--- output of version `python -Im \"ensurepip\"` command ---"
println output
println "------------------------------------------------------------"
allConditionsMet = false
} else {
println " OK"
}
} catch (Exception e) {
println "missing"
println "--- failed with exception ---"
println e
e.printStackTrace()
println "----------------------------------------------------"
allConditionsMet = false
}
}

// Check the python environment is setup correctly.
checkPython()
checkPythonVenv()

if (!allConditionsMet) {
throw new RuntimeException("Not all conditions met, see log for details.")
}
println ""
println "All known conditions met successfully."
println ""

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Calculate the version that we should use in the python build.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

def currentMavenVersion = project.version as String
def currentPythonVersion = currentMavenVersion
if(currentMavenVersion.contains("-SNAPSHOT")) {
currentPythonVersion = currentMavenVersion.split("-SNAPSHOT")[0] + ".dev"
}
println "Current Project Version in Maven: " + currentMavenVersion
println "Current Project Version in Python: " + currentPythonVersion

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Synchronize the version in pyproject.toml and the one used in the maven pom.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

def pyprojectFile = new File(project.basedir, "pyproject.toml")
def ts = new TomlSlurper()
def toml = ts.parse(pyprojectFile)
def pyprojectFileVersion = toml.tool.poetry.version
if (pyprojectFileVersion != currentPythonVersion) {
pyprojectFile.text = pyprojectFile.text.replace("version = \"" + pyprojectFileVersion + "\"", "version = \"" + currentPythonVersion + "\"")
println "Version in pyproject.toml updated from " + pyprojectFileVersion + " to " + currentPythonVersion
// TODO: When releasing, we might need to manually add this file to the release preparation commit.
} else {
println "Version in pyproject.toml is up to date"
}
14 changes: 13 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1354,7 +1354,7 @@
<execution>
<id>create-source-package</id>
<goals>
<goal>jar</goal>
<goal>jar-no-fork</goal>
</goals>
<phase>package</phase>
</execution>
Expand Down Expand Up @@ -1426,6 +1426,8 @@
<cmake.generator>Unix Makefiles</cmake.generator>
<os.classifier>linux-x86_64</os.classifier>
<thrift.executable>thrift</thrift.executable>
<python.venv.bin>venv/bin/</python.venv.bin>
<python.exe.bin>python3</python.exe.bin>
</properties>
</profile>
<profile>
Expand All @@ -1441,6 +1443,8 @@
<cmake.generator>Unix Makefiles</cmake.generator>
<os.classifier>linux-aarch64</os.classifier>
<thrift.executable>thrift</thrift.executable>
<python.venv.bin>venv/bin/</python.venv.bin>
<python.exe.bin>python3</python.exe.bin>
</properties>
</profile>
<profile>
Expand All @@ -1456,6 +1460,8 @@
<cmake.generator>Unix Makefiles</cmake.generator>
<os.classifier>mac-x86_64</os.classifier>
<thrift.executable>thrift</thrift.executable>
<python.venv.bin>venv/bin/</python.venv.bin>
<python.exe.bin>python3</python.exe.bin>
</properties>
</profile>
<profile>
Expand All @@ -1471,6 +1477,8 @@
<cmake.generator>Unix Makefiles</cmake.generator>
<os.classifier>mac-aarch64</os.classifier>
<thrift.executable>thrift</thrift.executable>
<python.venv.bin>venv/bin/</python.venv.bin>
<python.exe.bin>python3</python.exe.bin>
</properties>
</profile>
<profile>
Expand All @@ -1486,6 +1494,8 @@
<cmake.generator>Visual Studio 17 2022</cmake.generator>
<os.classifier>windows-x86_64</os.classifier>
<thrift.executable>Release/thrift.exe</thrift.executable>
<python.venv.bin>venv/Scripts/</python.venv.bin>
<python.exe.bin>python</python.exe.bin>
</properties>
</profile>
<profile>
Expand All @@ -1501,6 +1511,8 @@
<cmake.generator>Visual Studio 17 2022</cmake.generator>
<os.classifier>windows-aarch64</os.classifier>
<thrift.executable>Release/thrift.exe</thrift.executable>
<python.venv.bin>venv/Scripts/</python.venv.bin>
<python.exe.bin>python</python.exe.bin>
</properties>
</profile>
<profile>
Expand Down

0 comments on commit bde8d66

Please sign in to comment.