Files
update/software-client/software_client/v1/deploy.py
Bin Qian ebe177d918 USM deploy state
This change introduced state machines for release state, deploy state
and deploy host state.

This change removed the direct reference to the software metadata from
software-controller and other modules. Replaced with encapuslated
release_data module.

Also include changes:
1. removed required parameter for software deploy activate and software
deploy complete RestAPI.
2. ensure reload metadata for each request
3. added feed_repo and commit-id to the deploy entity, to be
   subsequently passed to deploy operations.
4. fix issues

TCs:
    passed: software upload major and patching releases
    passed: software deploy start major and patching releases
    passed: software deploy host (mock) major and patching release
    passed: software activate major and patching release
    passed: software complete major release and patching release
    passed: redeploy host after host deploy failed both major and
patching release

Story: 2010676
Task: 49849

Change-Id: I4b1894560eccb8ef4f613633a73bf3887b2b93fb
Signed-off-by: Bin Qian <bin.qian@windriver.com>
2024-04-17 16:40:07 +00:00

176 lines
5.1 KiB
Python

#
# Copyright (c) 2015-2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import re
import requests
import signal
import sys
import time
from software_client.common import base
from software_client.common import utils
from software_client import constants
class Deploy(base.Resource):
def __repr__(self):
return "<address pool %s>" % self._info
class DeployManager(base.Manager):
resource_class = Deploy
def precheck(self, args):
# args.deployment is a string
deployment = args.deployment
# args.region is a string
region_name = args.region_name
path = "/v1/software/deploy_precheck/%s" % (deployment)
if args.force:
path += "/force"
path += "?region_name=%s" % region_name
return self._create(path, body={})
def start(self, args):
# args.deployment is a string
deployment = args.deployment
# Ignore interrupts during this function
signal.signal(signal.SIGINT, signal.SIG_IGN)
# Issue deploy_start request
if args.force:
path = "/v1/software/deploy_start/%s/force" % (deployment)
else:
path = "/v1/software/deploy_start/%s" % (deployment)
return self._create(path, body={})
def host(self, args):
# args.deployment is a string
hostname = args.host
# Issue deploy_host request and poll for results
path = "/v1/software/deploy_host/%s" % (hostname)
if args.force:
path += "/force"
req, data = self._create(path, body={})
if req.status_code == 200:
if 'error' in data and data["error"] != "":
print("Error:")
print(data["error"])
rc = 1
else:
# NOTE(bqian) should consider return host_list instead.
rc = self.wait_for_install_complete(hostname)
elif req.status_code == 500:
print("An internal error has occurred. "
"Please check /var/log/software.log for details")
rc = 1
else:
m = re.search("(Error message:.*)", req.text, re.MULTILINE)
if m:
print(m.group(0))
else:
print("%s %s" % (req.status_code, req.reason))
rc = 1
return rc
def activate(self, args):
# Ignore interrupts during this function
signal.signal(signal.SIGINT, signal.SIG_IGN)
# Issue deploy_start request
path = "/v1/software/deploy_activate"
return self._create(path, body={})
def complete(self, args):
# Ignore interrupts during this function
signal.signal(signal.SIGINT, signal.SIG_IGN)
# Issue deploy_start request
path = "/v1/software/deploy_complete/"
return self._create(path, body={})
def host_list(self):
path = '/v1/software/host_list'
return self._list(path, "")
def show(self):
path = '/v1/software/deploy'
return self._list(path, "")
def wait_for_install_complete(self, hostname):
url = "/v1/software/host_list"
rc = 0
max_retries = 4
retriable_count = 0
while True:
# Sleep on the first pass as well, to allow time for the
# agent to respond
time.sleep(5)
try:
req, data = self._list(url)
except requests.exceptions.ConnectionError:
# The local software-controller may have restarted.
retriable_count += 1
if retriable_count > max_retries:
print("Lost communications with the software controller")
rc = 1
return rc
else:
break
if req.status_code == 200:
if not data:
print("Invalid host-list data returned:")
utils.print_result_debug(req, data)
rc = 1
host_state = None
for d in data:
if d['hostname'] == hostname:
host_state = d.get('host_state')
if host_state == constants.DEPLOYING:
print("\nDeployment started.")
rc = 0
elif host_state == constants.FAILED:
print("\nDeployment failed. Please check logs for details.")
rc = 1
elif host_state == constants.DEPLOYED:
print("\nDeployment was successful.")
rc = 0
elif host_state == constants.PENDING:
print("\nDeployment pending.")
else:
print("\nReported unknown state: %s" % host_state)
rc = 1
elif req.status_code == 500:
print("An internal error has occurred. Please check /var/log/software.log for details")
rc = 1
else:
m = re.search("(Error message:.*)", req.text, re.MULTILINE)
if m:
print(m.group(0))
else:
print(vars(req))
rc = 1
return rc