Decouple Guest-server/agent from stx-metal
This decouples the build and packaging of guest-server, guest-agent from mtce, by splitting guest component into stx-nfv repo. This leaves existing C++ code, scripts, and resource files untouched, so there is no functional change. Code refactoring is beyond the scope of this update. Makefiles were modified to include devel headers directories /usr/include/mtce-common and /usr/include/mtce-daemon. This ensures there is no contamination with other system headers. The cgts-mtce-common package is renamed and split into: - repo stx-metal: mtce-common, mtce-common-dev - repo stx-metal: mtce - repo stx-nfv: mtce-guest - repo stx-ha: updates package dependencies to mtce-pmon for service-mgmt, sm, and sm-api mtce-common: - contains common and daemon shared source utility code mtce-common-dev: - based on mtce-common, contains devel package required to build mtce-guest and mtce - contains common library archives and headers mtce: - contains components: alarm, fsmon, fsync, heartbeat, hostw, hwmon, maintenance, mtclog, pmon, public, rmon mtce-guest: - contains guest component guest-server, guest-agent Story: 2002829 Task: 22748 Depends-On: https://review.openstack.org/603435 Change-Id: I2ebaf07b94ee5b5abdf8f8db80536351ded22078 Signed-off-by: Jim Gauld <james.gauld@windriver.com>
This commit is contained in:
parent
2d39affda2
commit
d2b3e22a4e
@ -18,3 +18,7 @@ nfv-plugins
|
||||
nfv-tools
|
||||
nfv-vim
|
||||
nfv-client
|
||||
|
||||
# mtce-guest
|
||||
mtce-guestAgent
|
||||
mtce-guestServer
|
||||
|
@ -3,3 +3,4 @@ guest-client
|
||||
guest-agent
|
||||
guest-comm
|
||||
nfv
|
||||
mtce-guest
|
||||
|
13
mtce-guest/PKG-INFO
Normal file
13
mtce-guest/PKG-INFO
Normal file
@ -0,0 +1,13 @@
|
||||
Metadata-Version: 1.1
|
||||
Name: mtce-guest
|
||||
Version: 1.0
|
||||
Summary: Maintenance Guest Server/Agent Package
|
||||
Home-page:
|
||||
Author: Windriver
|
||||
Author-email: info@windriver.com
|
||||
License: Apache-2.0
|
||||
|
||||
Description: Maintenance Guest Server/Agent package containing daemons, resource and
|
||||
file system daemons, as well as support files for each.
|
||||
|
||||
Platform: UNKNOWN
|
3
mtce-guest/centos/build_srpm.data
Normal file
3
mtce-guest/centos/build_srpm.data
Normal file
@ -0,0 +1,3 @@
|
||||
SRC_DIR="src"
|
||||
TIS_PATCH_VER=139
|
||||
BUILD_IS_SLOW=5
|
222
mtce-guest/centos/mtce-guest.spec
Normal file
222
mtce-guest/centos/mtce-guest.spec
Normal file
@ -0,0 +1,222 @@
|
||||
Summary: Maintenance Guest Server/Agent Package
|
||||
Name: mtce-guest
|
||||
Version: 1.0
|
||||
%define patchlevel %{tis_patch_ver}
|
||||
Release: %{tis_patch_ver}%{?_tis_dist}
|
||||
|
||||
License: Apache-2.0
|
||||
Group: base
|
||||
Packager: Wind River <info@windriver.com>
|
||||
URL: unknown
|
||||
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
|
||||
BuildRequires: openssl
|
||||
BuildRequires: openssl-devel
|
||||
BuildRequires: json-c
|
||||
BuildRequires: json-c-devel
|
||||
BuildRequires: libevent
|
||||
BuildRequires: libevent-devel
|
||||
BuildRequires: libuuid
|
||||
BuildRequires: libuuid-devel
|
||||
BuildRequires: fm-common
|
||||
BuildRequires: fm-common-dev
|
||||
BuildRequires: guest-client-devel
|
||||
BuildRequires: mtce-common-dev >= 1.0
|
||||
BuildRequires: systemd-devel
|
||||
BuildRequires: cppcheck
|
||||
|
||||
%description
|
||||
Maintenance Guest Agent Service and Server assists in VM guest
|
||||
heartbeat control and failure reporting at the controller level.
|
||||
|
||||
%package -n mtce-guestAgent
|
||||
Summary: Maintenance Guest Agent Package
|
||||
Group: base
|
||||
Requires: dpkg
|
||||
Requires: time
|
||||
Requires: libjson-c.so.2()(64bit)
|
||||
Requires: libstdc++.so.6(CXXABI_1.3)(64bit)
|
||||
Requires: librt.so.1(GLIBC_2.2.5)(64bit)
|
||||
Requires: libfmcommon.so.1()(64bit)
|
||||
Requires: libstdc++.so.6(GLIBCXX_3.4.9)(64bit)
|
||||
Requires: fm-common >= 1.0
|
||||
Requires: libc.so.6(GLIBC_2.2.5)(64bit)
|
||||
Requires: libstdc++.so.6(GLIBCXX_3.4.11)(64bit)
|
||||
Requires: /bin/sh
|
||||
Requires: librt.so.1()(64bit)
|
||||
Requires: libc.so.6(GLIBC_2.3)(64bit)
|
||||
Requires: libc.so.6(GLIBC_2.14)(64bit)
|
||||
Requires: libpthread.so.0(GLIBC_2.2.5)(64bit)
|
||||
Requires: librt.so.1(GLIBC_2.3.3)(64bit)
|
||||
Requires: libgcc_s.so.1(GCC_3.0)(64bit)
|
||||
Requires: libevent >= 2.0.21
|
||||
Requires: libevent-2.0.so.5()(64bit)
|
||||
Requires: libuuid.so.1()(64bit)
|
||||
Requires: libm.so.6()(64bit)
|
||||
Requires: rtld(GNU_HASH)
|
||||
Requires: libstdc++.so.6()(64bit)
|
||||
Requires: libc.so.6()(64bit)
|
||||
Requires: libgcc_s.so.1()(64bit)
|
||||
Requires: libstdc++.so.6(GLIBCXX_3.4)(64bit)
|
||||
Requires: libstdc++.so.6(GLIBCXX_3.4.15)(64bit)
|
||||
Requires: libpthread.so.0()(64bit)
|
||||
|
||||
|
||||
%description -n mtce-guestAgent
|
||||
Maintenance Guest Agent Service assists in
|
||||
VM guest heartbeat control and failure reporting at the controller
|
||||
level.
|
||||
|
||||
%package -n mtce-guestServer
|
||||
Summary: Maintenance Guest Server Package
|
||||
Group: base
|
||||
Requires: util-linux
|
||||
Requires: /bin/bash
|
||||
Requires: /bin/systemctl
|
||||
Requires: dpkg
|
||||
Requires: libjson-c.so.2()(64bit)
|
||||
Requires: libstdc++.so.6(CXXABI_1.3)(64bit)
|
||||
Requires: librt.so.1(GLIBC_2.2.5)(64bit)
|
||||
Requires: libfmcommon.so.1()(64bit)
|
||||
Requires: libstdc++.so.6(GLIBCXX_3.4.9)(64bit)
|
||||
Requires: fm-common >= 1.0
|
||||
Requires: libc.so.6(GLIBC_2.2.5)(64bit)
|
||||
Requires: libstdc++.so.6(GLIBCXX_3.4.11)(64bit)
|
||||
Requires: /bin/sh
|
||||
Requires: librt.so.1()(64bit)
|
||||
Requires: libc.so.6(GLIBC_2.3)(64bit)
|
||||
Requires: libc.so.6(GLIBC_2.14)(64bit)
|
||||
Requires: libpthread.so.0(GLIBC_2.2.5)(64bit)
|
||||
Requires: librt.so.1(GLIBC_2.3.3)(64bit)
|
||||
Requires: libgcc_s.so.1(GCC_3.0)(64bit)
|
||||
Requires: libevent >= 2.0.21
|
||||
Requires: libevent-2.0.so.5()(64bit)
|
||||
Requires: libuuid.so.1()(64bit)
|
||||
Requires: libm.so.6()(64bit)
|
||||
Requires: rtld(GNU_HASH)
|
||||
Requires: libstdc++.so.6()(64bit)
|
||||
Requires: libc.so.6(GLIBC_2.4)(64bit)
|
||||
Requires: libc.so.6()(64bit)
|
||||
Requires: libgcc_s.so.1()(64bit)
|
||||
Requires: libstdc++.so.6(GLIBCXX_3.4)(64bit)
|
||||
Requires: libstdc++.so.6(GLIBCXX_3.4.15)(64bit)
|
||||
Requires: libpthread.so.0()(64bit)
|
||||
|
||||
%description -n mtce-guestServer
|
||||
Maintenance Guest Server assists in VM guest
|
||||
heartbeat control and failure reporting at the compute level.
|
||||
|
||||
%define local_dir /usr/local
|
||||
%define local_bindir %{local_dir}/bin
|
||||
%define local_sbindir %{local_dir}/sbin
|
||||
%define local_etc_pmond %{_sysconfdir}/pmon.d
|
||||
%define local_etc_servicesd %{_sysconfdir}/services.d
|
||||
%define local_etc_logrotated %{_sysconfdir}/logrotate.d
|
||||
%define ocf_resourced /usr/lib/ocf/resource.d
|
||||
|
||||
%prep
|
||||
%setup
|
||||
|
||||
# build mtce-guestAgent and mtce-guestServer package
|
||||
%build
|
||||
VER=%{version}
|
||||
MAJOR=$(echo $VER | awk -F . '{print $1}')
|
||||
MINOR=$(echo $VER | awk -F . '{print $2}')
|
||||
make MAJOR=$MAJOR MINOR=$MINOR %{?_smp_mflags} build
|
||||
|
||||
%global _buildsubdir %{_builddir}/%{name}-%{version}
|
||||
|
||||
# install mtce-guestAgent and mtce-guestServer package
|
||||
%install
|
||||
VER=%{version}
|
||||
MAJOR=$(echo $VER | awk -F . '{print $1}')
|
||||
MINOR=$(echo $VER | awk -F . '{print $2}')
|
||||
|
||||
install -m 755 -d %{buildroot}%{_sysconfdir}
|
||||
install -m 755 -d %{buildroot}/usr
|
||||
install -m 755 -d %{buildroot}/%{_bindir}
|
||||
install -m 755 -d %{buildroot}/usr/local
|
||||
install -m 755 -d %{buildroot}%{local_bindir}
|
||||
install -m 755 -d %{buildroot}/usr/local/sbin
|
||||
install -m 755 -d %{buildroot}/%{_sbindir}
|
||||
install -m 755 -d %{buildroot}/lib
|
||||
install -m 755 -d %{buildroot}%{_sysconfdir}/mtc
|
||||
install -m 755 -d %{buildroot}%{_sysconfdir}/mtc/tmp
|
||||
|
||||
# resource agent stuff
|
||||
install -m 755 -d %{buildroot}/usr/lib
|
||||
install -m 755 -d %{buildroot}/usr/lib/ocf
|
||||
install -m 755 -d %{buildroot}/usr/lib/ocf/resource.d
|
||||
install -m 755 -d %{buildroot}/usr/lib/ocf/resource.d/platform
|
||||
install -m 755 -p -D %{_buildsubdir}/scripts/guestAgent.ocf %{buildroot}/usr/lib/ocf/resource.d/platform/guestAgent
|
||||
|
||||
# config files
|
||||
install -m 644 -p -D %{_buildsubdir}/scripts/guest.ini %{buildroot}%{_sysconfdir}/mtc/guestAgent.ini
|
||||
install -m 644 -p -D %{_buildsubdir}/scripts/guest.ini %{buildroot}%{_sysconfdir}/mtc/guestServer.ini
|
||||
|
||||
# binaries
|
||||
install -m 755 -p -D %{_buildsubdir}/guestServer %{buildroot}/%{local_bindir}/guestServer
|
||||
install -m 755 -p -D %{_buildsubdir}/guestAgent %{buildroot}/%{local_bindir}/guestAgent
|
||||
|
||||
# init script files
|
||||
install -m 755 -p -D %{_buildsubdir}/scripts/guestServer %{buildroot}%{_sysconfdir}/init.d/guestServer
|
||||
install -m 755 -p -D %{_buildsubdir}/scripts/guestAgent %{buildroot}%{_sysconfdir}/init.d/guestAgent
|
||||
|
||||
# systemd service files
|
||||
install -m 644 -p -D %{_buildsubdir}/scripts/guestServer.service %{buildroot}%{_unitdir}/guestServer.service
|
||||
install -m 644 -p -D %{_buildsubdir}/scripts/guestAgent.service %{buildroot}%{_unitdir}/guestAgent.service
|
||||
|
||||
# process monitor config files
|
||||
install -m 755 -d %{buildroot}%{local_etc_pmond}
|
||||
install -m 644 -p -D %{_buildsubdir}/scripts/guestServer.pmon %{buildroot}%{local_etc_pmond}/guestServer.conf
|
||||
|
||||
# log rotation
|
||||
install -m 755 -d %{buildroot}%{_sysconfdir}/logrotate.d
|
||||
install -m 644 -p -D %{_buildsubdir}/scripts/guestAgent.logrotate %{buildroot}%{local_etc_logrotated}/guestAgent.logrotate
|
||||
install -m 644 -p -D %{_buildsubdir}/scripts/guestServer.logrotate %{buildroot}%{local_etc_logrotated}/guestServer.logrotate
|
||||
|
||||
# volatile directores
|
||||
install -m 755 -d %{buildroot}/var
|
||||
install -m 755 -d %{buildroot}/var/run
|
||||
|
||||
# enable all services in systemd
|
||||
%post -n mtce-guestServer
|
||||
/bin/systemctl enable guestServer.service
|
||||
|
||||
%files -n mtce-guestAgent
|
||||
%license LICENSE
|
||||
%defattr(-,root,root,-)
|
||||
|
||||
# create mtc and its tmp dir
|
||||
%dir %{_sysconfdir}/mtc
|
||||
%dir %{_sysconfdir}/mtc/tmp
|
||||
|
||||
# config files - non-modifiable
|
||||
%{_sysconfdir}/mtc/guestAgent.ini
|
||||
|
||||
%{_unitdir}/guestAgent.service
|
||||
%{local_etc_logrotated}/guestAgent.logrotate
|
||||
%{ocf_resourced}/platform/guestAgent
|
||||
|
||||
%{_sysconfdir}/init.d/guestAgent
|
||||
%{local_bindir}/guestAgent
|
||||
|
||||
%files -n mtce-guestServer
|
||||
%license LICENSE
|
||||
%defattr(-,root,root,-)
|
||||
|
||||
# create mtc and its tmp dir
|
||||
%dir %{_sysconfdir}/mtc
|
||||
%dir %{_sysconfdir}/mtc/tmp
|
||||
|
||||
# config files - non-modifiable
|
||||
%{_sysconfdir}/mtc/guestServer.ini
|
||||
|
||||
%{local_etc_pmond}/guestServer.conf
|
||||
%{local_etc_logrotated}/guestServer.logrotate
|
||||
%{_unitdir}/guestServer.service
|
||||
|
||||
%{_sysconfdir}/init.d/guestServer
|
||||
%{local_bindir}/guestServer
|
||||
|
202
mtce-guest/src/LICENSE
Normal file
202
mtce-guest/src/LICENSE
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
36
mtce-guest/src/Makefile
Normal file
36
mtce-guest/src/Makefile
Normal file
@ -0,0 +1,36 @@
|
||||
#
|
||||
# Copyright (c) 2015-2016 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
SRCS = guestClass.cpp guestInstClass.cpp \
|
||||
guestSvrFsm.cpp guestSvrHdlr.cpp \
|
||||
guestServer.cpp guestAgent.cpp \
|
||||
guestHttpSvr.cpp guestHttpUtil.cpp guestVimApi.cpp \
|
||||
guestUtil.cpp guestSvrUtil.cpp guestSvrMsg.cpp \
|
||||
guestVirtio.cpp guestStubs.cpp
|
||||
AGENT_OBJS = \
|
||||
guestAgent.o guestClass.o guestHttpSvr.o guestHttpUtil.o guestVimApi.o guestUtil.o guestStubs.o
|
||||
SERVER_OBJS = \
|
||||
guestServer.o guestInstClass.o \
|
||||
guestSvrFsm.o guestSvrHdlr.o \
|
||||
guestSvrMsg.o guestVirtio.o \
|
||||
guestUtil.o guestSvrUtil.o
|
||||
|
||||
OBJS = $(SRCS:.cpp=.o)
|
||||
|
||||
CCPFLAGS = -g -O2 -Wall -Wextra -Werror
|
||||
LDLIBS = -lstdc++ -ldaemon -lcommon -lfmcommon -ljson-c -levent -lrt -lcrypto -luuid
|
||||
INCLUDES = -I. -I/usr/include/mtce-common -I/usr/include/mtce-daemon
|
||||
|
||||
build: $(OBJS)
|
||||
$(CXX) $(CCPFLAGS) $(AGENT_OBJS) $(LDLIBS) -L. -o guestAgent
|
||||
$(CXX) $(CCPFLAGS) $(SERVER_OBJS) $(LDLIBS) -L. -o guestServer
|
||||
|
||||
.cpp.o:
|
||||
$(CXX) $(INCLUDES) $(CCPFLAGS) $(EXTRACCFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
@rm -v -f $(OBJ) guestAgent guestServer *.o *.a
|
||||
|
67
mtce-guest/src/README.txt
Normal file
67
mtce-guest/src/README.txt
Normal file
@ -0,0 +1,67 @@
|
||||
This maintenance common guest service provides a means of guest heartbeat
|
||||
orchestration under VIM (system management) control.
|
||||
|
||||
1. Packaging and Initialization:
|
||||
|
||||
The packaging of the heartbeat daemon and heartbeat_init
|
||||
script are modified:
|
||||
|
||||
a. image.inc and filter_out packaging files are modified to exclude the
|
||||
heartbeat daemon from being packaged on the controller.
|
||||
|
||||
b. because the heartbeat daemon is still packaged on the compute
|
||||
heartbeat_init script is modified to prevent the heartbeat
|
||||
daemon from being spawned on the compute host.
|
||||
|
||||
2. Compute Function: Heartbeats the guest and reports failures.
|
||||
|
||||
Package: cgts-mtce-common-guestServer-1.0-r54.0.x86_64.rpm
|
||||
Binary: /usr/local/bin/guestServer
|
||||
Init: /etc/init.d/guestServer
|
||||
Managed: /etc/pmon.d/guestServer.pmon
|
||||
|
||||
3. Controller Function: Guest heartbeat control and event proxy
|
||||
|
||||
Package: cgts-mtce-common-guestAgent-x.x-rxx.x86_64.rpm
|
||||
Binary: /usr/local/bin/guestAgent
|
||||
Init: /usr/lib/ocf/resource.d/platform/guestAgent
|
||||
Managed: by SM
|
||||
|
||||
The heartbeat daemon that did run on the controller is replaced by a new
|
||||
guestAgent daemon performing the following functions
|
||||
|
||||
a. HTTP Command Receiver : to which the VIM sends instance control commands.
|
||||
b. HTTP Event Transmitter: to which the daemon can send instance failure
|
||||
events and state query commands to the VIM.
|
||||
c. State query audit
|
||||
|
||||
Behavioral Executive Summary:
|
||||
|
||||
The guestServer daemon (on the compute) listens for (using inotify) 'uuid'
|
||||
UNIX named heartbeat communication channels that nova:libvirt creates and
|
||||
opens in /var/lib/libvirt/qemu whenever an instance is created. Example:
|
||||
|
||||
/var/lib/libvirt/qemu/cgcs.heartbeat.02e172a9-aeae-4cef-a6bc-7eb9de7825d6.sock
|
||||
|
||||
The guestServer connects (and auto reconnects) to these channels when they are
|
||||
created or modified and disconnects from them when deleted.
|
||||
|
||||
Once connected, the guestServer listens for TCP messages over that UNIX named
|
||||
socket.
|
||||
|
||||
If a guest supports heartbeating then it will run the heartbeat_init script
|
||||
during its initialization process. Once the heartbeat daemon is running it
|
||||
will periodically send init request messages to the libvirt pipe that,
|
||||
on the host side, the guestServer is listening for.
|
||||
|
||||
on receipt of an init message, the guestServer will extract name, timeout
|
||||
and corrective action info from it and then send back an 'init_ack' followed
|
||||
by a continuous heartbeat cycle consisting of sending a 'challenge' request
|
||||
messages and expecting a correct computational responses within a guest specified
|
||||
heartbeat window. Failure to comply will result in a corrective action that was
|
||||
specified in the init message from the guest.
|
||||
|
||||
The VIM is responsible for enabling and disabling heartbeat fault reporting as
|
||||
well as taking the guest specified corrective action in he event of a heartbeat
|
||||
failure.
|
||||
|
1429
mtce-guest/src/guestAgent.cpp
Normal file
1429
mtce-guest/src/guestAgent.cpp
Normal file
File diff suppressed because it is too large
Load Diff
319
mtce-guest/src/guestBase.h
Normal file
319
mtce-guest/src/guestBase.h
Normal file
@ -0,0 +1,319 @@
|
||||
#ifndef __INCLUDE_GUESTBASE_H__
|
||||
#define __INCLUDE_GUESTBASE_H__
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013-2016 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Wind River CGTS Platform Guest Services "Base" Header
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <signal.h>
|
||||
#include <list>
|
||||
|
||||
#include <guest-client/guest_heartbeat_msg_defs.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "msgClass.h"
|
||||
#include "nodeBase.h"
|
||||
#include "httpUtil.h"
|
||||
#include "nodeTimers.h"
|
||||
|
||||
#define WANT_NEW
|
||||
|
||||
/**
|
||||
* @addtogroup guest_services_base
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef __AREA__
|
||||
#undef __AREA__
|
||||
#endif
|
||||
#define __AREA__ "gst"
|
||||
|
||||
#define CONFIG_CLIENT_RX_PORT (0x00000001)
|
||||
#define CONFIG_MTC_EVENT_PORT (0x00000002)
|
||||
#define CONFIG_MTC_CMD_PORT (0x00000004)
|
||||
#define CONFIG_AGENT_RX_PORT (0x00000008)
|
||||
#define CONFIG_VIM_CMD_RX_PORT (0x00000010)
|
||||
#define CONFIG_VIM_EVENT_RX_PORT (0x00000020)
|
||||
|
||||
#define HB_DEFAULT_FIRST_MS 2000
|
||||
#define HB_DEFAULT_INTERVAL_MS 1000
|
||||
#define HB_DEFAULT_REBOOT_MS 10000
|
||||
#define HB_DEFAULT_VOTE_MS 10000
|
||||
#define HB_DEFAULT_SHUTDOWN_MS 10000
|
||||
#define HB_DEFAULT_SUSPEND_MS 10000
|
||||
#define HB_DEFAULT_RESUME_MS 10000
|
||||
#define HB_DEFAULT_RESTART_MS 120000
|
||||
|
||||
/* Directory where libvirt creates the serial I/O pipe channel sockets into the guest
|
||||
* We monitor this directory with inotify for file changes */
|
||||
#define QEMU_CHANNEL_DIR ((const char *)"/var/lib/libvirt/qemu")
|
||||
|
||||
#define ARRAY_SIZE(x) ((int)(sizeof(x)/sizeof(*x)))
|
||||
|
||||
#define MAX_INSTANCES (100)
|
||||
#define MAX_MESSAGES (10)
|
||||
|
||||
/* The socket select timeout */
|
||||
#define GUEST_SOCKET_TO (10000)
|
||||
|
||||
#define DEFAULT_CONNECT_WAIT (1)
|
||||
|
||||
#define CONNECT_TIMOUT (60)
|
||||
#define WAIT_FOR_INIT_TIMEOUT (60)
|
||||
#define HEARTBEAT_START_TIMEOUT (120)
|
||||
#define SEARCH_AUDIT_TIME (180)
|
||||
|
||||
void guestTimer_handler ( int sig, siginfo_t *si, void *uc);
|
||||
|
||||
const char * get_guest_msg_hdr (void) ;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char buffer [256];
|
||||
} gst_message_type ;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
hbs_invalid,
|
||||
hbs_server_waiting_init,
|
||||
hbs_server_waiting_challenge,
|
||||
hbs_server_waiting_response,
|
||||
hbs_server_paused, // heartbeat paused at request of vm
|
||||
hbs_server_nova_paused, // heartbeat paused at request of nova
|
||||
hbs_server_migrating, // heartbeat paused while migrate in progress
|
||||
hbs_server_corrective_action,
|
||||
hbs_client_waiting_init_ack,
|
||||
hbs_client_waiting_challenge,
|
||||
hbs_client_waiting_pause_ack,
|
||||
hbs_client_waiting_resume_ack,
|
||||
hbs_client_paused,
|
||||
hbs_client_waiting_shutdown_ack,
|
||||
hbs_client_waiting_shutdown_response,
|
||||
hbs_client_shutdown_response_recieved,
|
||||
hbs_client_exiting,
|
||||
hbs_state_max
|
||||
} hb_state_t;
|
||||
|
||||
/** Guest service control messaging socket control structure */
|
||||
typedef struct
|
||||
{
|
||||
/** Guest Services Messaging Agent Receive (from guestServer) Socket
|
||||
*
|
||||
* Note: This socket supports receiving from the computes specifying
|
||||
* either the floating or local IP */
|
||||
int agent_rx_port ;
|
||||
msgClassSock* agent_rx_float_sock ;
|
||||
msgClassSock* agent_rx_local_sock ;
|
||||
|
||||
/** Guest Services Messaging Agent Transmit (to guestServer) Socket
|
||||
*
|
||||
* Note: This transmit socket can be used for any port
|
||||
* specified at send time */
|
||||
msgClassSock* agent_tx_sock ;
|
||||
|
||||
|
||||
/** Guest Services Messaging Socket mtcAgent commands are received on */
|
||||
msgClassSock* mtc_cmd_sock ;
|
||||
int mtc_cmd_port ;
|
||||
|
||||
/** Guest Services Messaging Server Receive (from guestAgent) Socket */
|
||||
msgClassSock* server_rx_sock ;
|
||||
int server_rx_port ;
|
||||
|
||||
/** Guest Services Messaging Server Transmit (to guestAgent) Socket */
|
||||
msgClassSock* server_tx_sock ;
|
||||
struct sockaddr_in server_tx_addr ;
|
||||
|
||||
/** Socket used to transmit READY status and Events to Maintenance */
|
||||
int mtc_event_tx_port ;
|
||||
msgClassSock* mtc_event_tx_sock ;
|
||||
|
||||
int netlink_sock ; /* netlink socket */
|
||||
int ioctl_sock ; /* general ioctl socket */
|
||||
|
||||
msgSock_type mtclogd ;
|
||||
} guest_services_socket_type ;
|
||||
|
||||
/**
|
||||
* The HTTP server supports two URL levels ;
|
||||
* a hosts level and instances level.
|
||||
**/
|
||||
typedef enum
|
||||
{
|
||||
SERVICE_LEVEL_NONE,
|
||||
SERVICE_LEVEL_HOST,
|
||||
SERVICE_LEVEL_INST,
|
||||
} service_level_enum ;
|
||||
|
||||
/** common service_type control info */
|
||||
typedef struct
|
||||
{
|
||||
bool provisioned ; /* set true once the VIM issues create */
|
||||
string state ; /* enabled, configured or disabled */
|
||||
bool reporting ; /* failue reporting state */
|
||||
|
||||
int failures ; /* Running count of failures */
|
||||
bool failed ; /* true means heartbeating has failed */
|
||||
bool waiting ; /* Waiting on a response */
|
||||
int b2b_misses ; /* running back-to-back misses */
|
||||
} service_type ;
|
||||
|
||||
/** A grouping of info extracted from command's url */
|
||||
typedef struct
|
||||
{
|
||||
service_level_enum service_level ;
|
||||
string uuid ;
|
||||
string command ;
|
||||
string temp ;
|
||||
} url_info_type ;
|
||||
|
||||
/** instance control structure */
|
||||
typedef struct
|
||||
{
|
||||
string hostname ; /**< The host that this instance is on */
|
||||
|
||||
/* Instance identifiers */
|
||||
string name ; /**< the Instance Name as it appears in the GUI */
|
||||
string uuid ; /**< the instance uuid which is unique to the system */
|
||||
string chan ; /**< virtio channel name 'cgcs.heartbeat.<uuid>.sock' */
|
||||
string inst ; /**< the instance part of the channel name */
|
||||
|
||||
/* Set to true when this channel has been provisioned by the guestAgent */
|
||||
// bool provisioned ;
|
||||
|
||||
/*
|
||||
* Full path and name to the detected channel.
|
||||
* Used to set inotify file watch.
|
||||
*/
|
||||
string fd_namespace ;
|
||||
|
||||
#define CHAN_FLAGS (SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC )
|
||||
int chan_fd ;
|
||||
bool chan_ok ;
|
||||
|
||||
bool connecting ;
|
||||
bool connected ; /* true = the channel is connected to the guest */
|
||||
bool heartbeating ; /* true = the heartbeating has started */
|
||||
|
||||
string name_log_prefix ;
|
||||
string uuid_log_prefix ;
|
||||
|
||||
int connect_wait_in_secs ;
|
||||
|
||||
/* added service bools */
|
||||
service_type heartbeat ;
|
||||
service_type reserved ;
|
||||
|
||||
/*
|
||||
* File and watch descriptors used to monitor
|
||||
* specific files in QEMU_CHANNEL_DIR
|
||||
*/
|
||||
int inotify_file_fd ;
|
||||
int inotify_file_wd ;
|
||||
|
||||
/* Message header info */
|
||||
int version;
|
||||
int revision;
|
||||
string msg_type;
|
||||
uint32_t sequence;
|
||||
|
||||
hb_state_t hbState ; /* see heartbeat_types.h */
|
||||
hb_state_t vnState ; /* see heartbeat_types.h */
|
||||
|
||||
uint32_t invocation_id ;
|
||||
|
||||
// For voting and notification
|
||||
string event_type; // GuestHeartbeatMsgEventT
|
||||
string notification_type; // GuestHeartbeatMsgNotifyT
|
||||
|
||||
uint32_t heartbeat_challenge ;
|
||||
uint32_t heartbeat_interval_ms ;
|
||||
|
||||
uint32_t vote_secs;
|
||||
uint32_t shutdown_notice_secs;
|
||||
uint32_t suspend_notice_secs;
|
||||
uint32_t resume_notice_secs;
|
||||
uint32_t restart_secs;
|
||||
string corrective_action;
|
||||
|
||||
string unhealthy_corrective_action;
|
||||
bool unhealthy_failure ;
|
||||
|
||||
/* String versions of the above timeouts - integer portions only */
|
||||
string vote_to_str ; /* vote timeout in seconds as a string value */
|
||||
string shutdown_to_str ; /* shutdown timeout in seconds as a string value */
|
||||
string suspend_to_str ; /* suspend timeout in seconds as a string value */
|
||||
string resume_to_str ; /* resume timeout in seconds as a string value */
|
||||
string restart_to_str ; /* restart timeout in seconds as a string value */
|
||||
|
||||
int select_count ;
|
||||
int message_count ;
|
||||
int health_count ;
|
||||
int failure_count ;
|
||||
int connect_count ;
|
||||
int connect_retry_count ;
|
||||
int corrective_action_count ;
|
||||
|
||||
libEvent vimEvent ;
|
||||
|
||||
} instInfo ;
|
||||
|
||||
/* daemon control structure - used for both guestAgent and guestServer */
|
||||
typedef struct
|
||||
{
|
||||
bool init ;
|
||||
char hostname [MAX_HOST_NAME_SIZE+1];
|
||||
string address ;
|
||||
string address_peer ; /* used for server only */
|
||||
int nodetype ; /* used for server only */
|
||||
|
||||
guest_services_socket_type sock ;
|
||||
struct mtc_timer timer ;
|
||||
|
||||
/* List of instances provisioned on this host */
|
||||
list<instInfo> instance_list ; /* used for server only */
|
||||
list<instInfo>::iterator instance_list_ptr; /* used for server only */
|
||||
|
||||
/* file and watch descriptors used to monitor QEMU_CHANNEL_DIR */
|
||||
int inotify_dir_fd ;
|
||||
int inotify_dir_wd ;
|
||||
|
||||
|
||||
|
||||
} ctrl_type ;
|
||||
|
||||
ctrl_type * get_ctrl_ptr ( void );
|
||||
|
||||
|
||||
|
||||
int send_cmd_to_guestServer ( string hostname, unsigned int cmd, string uuid, bool reporting, string event="unknown" );
|
||||
|
||||
/**
|
||||
* @} guest_services_base
|
||||
*/
|
||||
|
||||
#endif /* __INCLUDE_GUESTBASE_H__ */
|
1335
mtce-guest/src/guestClass.cpp
Normal file
1335
mtce-guest/src/guestClass.cpp
Normal file
File diff suppressed because it is too large
Load Diff
202
mtce-guest/src/guestClass.h
Normal file
202
mtce-guest/src/guestClass.h
Normal file
@ -0,0 +1,202 @@
|
||||
#ifndef __INCLUDE_GUESTCLASS_H__
|
||||
#define __INCLUDE_GUESTCLASS_H__
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
#include "guestBase.h"
|
||||
#include "httpUtil.h" /* for ... libEvent and httpUtil_... */
|
||||
#include "hostClass.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STAGE__START,
|
||||
STAGES
|
||||
} guest_stage_enum ;
|
||||
|
||||
|
||||
class guestHostClass
|
||||
{
|
||||
private:
|
||||
struct guest_host {
|
||||
|
||||
/** Pointer to the previous / next host in the list */
|
||||
struct guest_host * prev;
|
||||
struct guest_host * next;
|
||||
|
||||
string hostname ;
|
||||
string uuid ;
|
||||
string ip ;
|
||||
int hosttype ;
|
||||
|
||||
/**
|
||||
* Top level gate for the host.
|
||||
* If false then reporting for all instances are off.
|
||||
*/
|
||||
bool reporting;
|
||||
|
||||
bool query_flag ;
|
||||
int query_misses ;
|
||||
|
||||
/** Instance level Audit timer */
|
||||
struct mtc_timer host_audit_timer;
|
||||
|
||||
/** flag that indicates we were able to fetch host state from the VIM */
|
||||
bool got_host_state ;
|
||||
|
||||
/** flag that indicates we were able to fetch intances from the VIM */
|
||||
bool got_instances ;
|
||||
|
||||
/** Main FSM stage */
|
||||
guest_stage_enum stage ;
|
||||
|
||||
/* List of instances for this host */
|
||||
list<instInfo> instance_list ;
|
||||
list<instInfo>::iterator instance_list_ptr;
|
||||
|
||||
libEvent vimEvent ;
|
||||
};
|
||||
|
||||
/** List of allocated host memory.
|
||||
*
|
||||
* An array of host pointers.
|
||||
*/
|
||||
guest_host * host_ptrs[MAX_HOSTS] ;
|
||||
|
||||
/** A memory allocation counter.
|
||||
*
|
||||
* Should represent the number of hosts in the linked list.
|
||||
*/
|
||||
int memory_allocs ;
|
||||
|
||||
/** A memory used counter
|
||||
*
|
||||
* A variable storing the accumulated host memory
|
||||
*/
|
||||
int memory_used ;
|
||||
|
||||
|
||||
// struct hostBaseClass::host* getHost ( string hostname );
|
||||
|
||||
struct guest_host * guest_head ; /**< Host Linked List Head pointer */
|
||||
struct guest_host * guest_tail ; /**< Host Linked List Tail pointer */
|
||||
|
||||
struct guestHostClass::guest_host* newHost ( void );
|
||||
struct guestHostClass::guest_host* addHost ( string hostname );
|
||||
struct guestHostClass::guest_host* getHost ( string hostname );
|
||||
int remHost ( string hostname );
|
||||
int delHost ( struct guestHostClass::guest_host * guest_host_ptr );
|
||||
struct guestHostClass::guest_host* getHost_timer ( timer_t tid );
|
||||
|
||||
libEvent & getEvent ( struct event_base * base_ptr, string & hostname );
|
||||
|
||||
const
|
||||
char * get_guestStage_str ( struct guestHostClass::guest_host * guest_host_ptr );
|
||||
int guestStage_change ( struct guestHostClass::guest_host * guest_host_ptr, guest_stage_enum newStage );
|
||||
|
||||
void mem_log_info ( void );
|
||||
void mem_log_info_host ( struct guestHostClass::guest_host * guest_host_ptr );
|
||||
void mem_log_info_inst ( struct guestHostClass::guest_host * guest_host_ptr );
|
||||
|
||||
public:
|
||||
|
||||
guestHostClass(); /**< constructor */
|
||||
~guestHostClass(); /**< destructor */
|
||||
|
||||
hostBaseClass hostBase ;
|
||||
|
||||
bool exit_fsm ;
|
||||
void run_fsm ( string hostname );
|
||||
|
||||
bool audit_run ;
|
||||
|
||||
/** Host level Audit timer */
|
||||
struct mtc_timer audit_timer;
|
||||
|
||||
/** This is a list of host names. */
|
||||
std::list<string> hostlist ;
|
||||
std::list<string>::iterator hostlist_iter_ptr ;
|
||||
|
||||
// void guest_fsm ( void );
|
||||
|
||||
int hosts ;
|
||||
|
||||
/* For select dispatch */
|
||||
struct timeval waitd ;
|
||||
|
||||
fd_set inotify_readfds ;
|
||||
fd_set instance_readfds ;
|
||||
fd_set message_readfds ;
|
||||
|
||||
int add_host ( string uuid, string address, string hostname, string nodetype );
|
||||
int mod_host ( string uuid, string address, string hostname, string nodetype );
|
||||
int del_host ( string hostname ); /* delete the host from the daemon - mtcAgent */
|
||||
int rem_host ( string hostname );
|
||||
|
||||
/** Delete all instances for this host */
|
||||
int del_host_inst ( string host_uuid );
|
||||
|
||||
int add_inst ( string hostname, instInfo & instance );
|
||||
int mod_inst ( string hostname, instInfo & instance );
|
||||
int del_inst ( string instance );
|
||||
instInfo * get_inst ( string instance );
|
||||
|
||||
/* The handler that lib event calls to handle the return response */
|
||||
void guestVimApi_handler ( struct evhttp_request *req, void *arg );
|
||||
|
||||
/**
|
||||
* Change all the instance service states to enabled or disable
|
||||
* for the specified host.
|
||||
**/
|
||||
int host_inst( string hostname , mtc_cmd_enum command );
|
||||
|
||||
/**
|
||||
* Set and Get a bool that indicates whether we already
|
||||
* got the host reporting state from the VIM.
|
||||
*
|
||||
* The VIM might not be running at the time this daemon
|
||||
* is started so we need to retry until we get it
|
||||
**/
|
||||
void set_got_host_state ( string hostname );
|
||||
bool get_got_host_state ( string hostname );
|
||||
void set_got_instances ( string hostname );
|
||||
bool get_got_instances ( string hostname );
|
||||
|
||||
/** returns he number of instances on this host */
|
||||
int num_instances ( string hostname );
|
||||
|
||||
string get_host_name ( string host_uuid );
|
||||
string get_host_uuid ( string hostname );
|
||||
string get_host_ip ( string hostname );
|
||||
string get_inst_host_name ( string instance_uuid );
|
||||
|
||||
/* Send the instance reporting state to the guestServer on that host
|
||||
* primarily used to preiodically refresh instance reporting state or
|
||||
* set it when the guestServer seems to have restarted */
|
||||
int set_inst_state ( string hostname );
|
||||
|
||||
libEvent & get_host_event ( string hostname );
|
||||
|
||||
void inc_query_misses ( string hostname );
|
||||
void clr_query_misses ( string hostname );
|
||||
int get_query_misses ( string hostname );
|
||||
void set_query_flag ( string hostname );
|
||||
void clr_query_flag ( string hostname );
|
||||
bool get_query_flag ( string hostname );
|
||||
|
||||
bool get_reporting_state( string hostname );
|
||||
int set_reporting_state( string hostname, bool enabled );
|
||||
|
||||
void memLogDelimit ( void ); /**< Debug log delimiter */
|
||||
void memDumpNodeState ( string hostname );
|
||||
void memDumpAllState ( void );
|
||||
void print_node_info ( void ); /**< Print node info banner */
|
||||
};
|
||||
|
||||
guestHostClass * get_hostInv_ptr ( void );
|
||||
|
||||
#endif /* __INCLUDE_GUESTCLASS_H__ */
|
1092
mtce-guest/src/guestHttpSvr.cpp
Normal file
1092
mtce-guest/src/guestHttpSvr.cpp
Normal file
File diff suppressed because it is too large
Load Diff
27
mtce-guest/src/guestHttpSvr.h
Normal file
27
mtce-guest/src/guestHttpSvr.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2015 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Wind River CGTS Platform Controller Maintenance Daemon
|
||||
*/
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct sockaddr_in addr ;
|
||||
struct event_base * base ;
|
||||
struct evhttp_request * req ;
|
||||
struct evhttp * httpd ;
|
||||
int fd ;
|
||||
int port ;
|
||||
} request_type ;
|
||||
|
||||
void guestHttpSvr_fini ( void );
|
||||
int guestHttpSvr_init ( int port );
|
||||
int guestHttpSvr_setup ( request_type & request );
|
||||
void guestHttpSvr_look ( void );
|
227
mtce-guest/src/guestHttpUtil.cpp
Normal file
227
mtce-guest/src/guestHttpUtil.cpp
Normal file
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2015 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Wind River CGTS Platform Controller Maintenance HTTP Utilities.
|
||||
*
|
||||
* Public Interfaces:
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <evhttp.h>
|
||||
#include <list>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "httpUtil.h" /* for ... common http utilities */
|
||||
#include "jsonUtil.h" /* for ... Json Utilities */
|
||||
#include "nodeUtil.h" /* for ... Node Utilities */
|
||||
|
||||
#include "guestClass.h" /* for ... maintenance class nodeLinkClass */
|
||||
#include "guestHttpUtil.h" /* for ... this module header */
|
||||
#include "guestVimApi.h" /* for ... guestVimApi_Handler */
|
||||
|
||||
/* Module init */
|
||||
void guestHttpUtil_init ( void )
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
/* Module close */
|
||||
void guestHttpUtil_fini ( void )
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
/* *********************************************************************
|
||||
*
|
||||
* Name : guestHttpUtil_status
|
||||
*
|
||||
* Description: Extracts and returns the HTTP execution status
|
||||
*
|
||||
* *********************************************************************/
|
||||
|
||||
int guestHttpUtil_status ( libEvent & event )
|
||||
{
|
||||
int rc = PASS ;
|
||||
|
||||
if ( !event.req )
|
||||
{
|
||||
elog ("%s Invalid request\n", event.hostname.length() ? event.hostname.c_str() : "unknown" );
|
||||
return (FAIL_UNKNOWN_HOSTNAME);
|
||||
}
|
||||
event.status = event.http_status = evhttp_request_get_response_code (event.req);
|
||||
switch (event.status)
|
||||
{
|
||||
case HTTP_OK:
|
||||
case 201:
|
||||
case 202:
|
||||
case 203:
|
||||
case 204:
|
||||
{
|
||||
dlog ("%s HTTP_OK (%d)\n", event.hostname.c_str(), event.status );
|
||||
event.status = PASS ;
|
||||
break;
|
||||
}
|
||||
/* Authentication error - refresh the token */
|
||||
case 401:
|
||||
{
|
||||
rc = FAIL_AUTHENTICATION ;
|
||||
break ;
|
||||
}
|
||||
case 0:
|
||||
{
|
||||
wlog ("%s Status:0 - failed to connect to '%s:%d'\n",
|
||||
event.hostname.c_str(), event.ip.c_str(), event.port);
|
||||
event.status = FAIL_HTTP_ZERO_STATUS ;
|
||||
rc = FAIL_HTTP_ZERO_STATUS ;
|
||||
break ;
|
||||
}
|
||||
default:
|
||||
{
|
||||
dlog3 ("%s Status: %d\n", event.hostname.c_str(), event.status );
|
||||
rc = event.status ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/* ***********************************************************************
|
||||
*
|
||||
* Name : guestHttpUtil_api_req
|
||||
*
|
||||
* Description: Makes an HTTP request based on all the info
|
||||
* in the supplied libEvent.
|
||||
*
|
||||
* ************************************************************************/
|
||||
int guestHttpUtil_api_req ( libEvent & event )
|
||||
|
||||
{
|
||||
http_headers_type hdrs ;
|
||||
bool has_payload = false;
|
||||
int hdr_entry = 0 ;
|
||||
int rc = FAIL ;
|
||||
void(*handler)(struct evhttp_request *, void *) = NULL ;
|
||||
|
||||
/* Bind the unlock handler */
|
||||
handler = &guestVimApi_Handler;
|
||||
|
||||
/* set the timeout */
|
||||
event.timeout = HTTP_VIM_TIMEOUT ;
|
||||
|
||||
/* Check for memory leaks */
|
||||
if ( event.base )
|
||||
{
|
||||
slog ("%s http base memory leak avoidance (%p) fixme !!\n",
|
||||
event.log_prefix.c_str(), event.base );
|
||||
// event_base_free(event.base);
|
||||
}
|
||||
|
||||
/* Allocate the base */
|
||||
event.base = event_base_new();
|
||||
if ( event.base == NULL )
|
||||
{
|
||||
elog ("%s No Memory for Request\n", event.log_prefix.c_str());
|
||||
return ( FAIL_EVENT_BASE );
|
||||
}
|
||||
|
||||
/* Establish connection */
|
||||
else if ( httpUtil_connect ( event ))
|
||||
{
|
||||
return (FAIL_CONNECT);
|
||||
}
|
||||
|
||||
else if ( httpUtil_request ( event, handler ))
|
||||
{
|
||||
return (FAIL_REQUEST_NEW);
|
||||
}
|
||||
|
||||
jlog ("%s Address : %s\n", event.hostname.c_str(), event.token.url.c_str());
|
||||
|
||||
if ((( event.type != EVHTTP_REQ_GET ) && ( event.type != EVHTTP_REQ_DELETE )) ||
|
||||
( event.request == VIM_HOST_STATE_QUERY ))
|
||||
{
|
||||
has_payload = true ;
|
||||
|
||||
/* Add payload to the output buffer but only for PUT, POST and PATCH requests */
|
||||
if ( httpUtil_payload_add ( event ))
|
||||
{
|
||||
return (FAIL_PAYLOAD_ADD);
|
||||
}
|
||||
jlog ("%s Payload : %s\n", event.hostname.c_str(),
|
||||
event.payload.c_str() );
|
||||
}
|
||||
|
||||
/* Convert port to a string */
|
||||
char port_str[10] ;
|
||||
sprintf ( port_str, "%d", event.port );
|
||||
|
||||
/* Build the HTTP Header */
|
||||
hdrs.entry[hdr_entry].key = "Host" ;
|
||||
hdrs.entry[hdr_entry].value = event.ip ;
|
||||
hdrs.entry[hdr_entry].value.append(":") ;
|
||||
hdrs.entry[hdr_entry].value.append(port_str);
|
||||
hdr_entry++;
|
||||
|
||||
if ( has_payload == true )
|
||||
{
|
||||
hdrs.entry[hdr_entry].key = "Content-Length" ;
|
||||
hdrs.entry[hdr_entry].value = httpUtil_payload_len ( &event );
|
||||
hdr_entry++;
|
||||
}
|
||||
|
||||
hdrs.entry[hdr_entry].key = "User-Agent" ;
|
||||
hdrs.entry[hdr_entry].value = "guest-agent/1.0" ;
|
||||
hdr_entry++;
|
||||
|
||||
hdrs.entry[hdr_entry].key = "Content-Type" ;
|
||||
hdrs.entry[hdr_entry].value = "application/json" ;
|
||||
hdr_entry++;
|
||||
|
||||
hdrs.entry[hdr_entry].key = "Connection" ;
|
||||
hdrs.entry[hdr_entry].value = "close" ;
|
||||
hdr_entry++;
|
||||
hdrs.entries = hdr_entry ;
|
||||
|
||||
/* Add the headers */
|
||||
if ( httpUtil_header_add ( &event, &hdrs ))
|
||||
{
|
||||
return (FAIL_HEADER_ADD);
|
||||
}
|
||||
|
||||
event.address = event.token.url ;
|
||||
|
||||
rc = evhttp_make_request ( event.conn, event.req, event.type, event.token.url.data());
|
||||
if ( rc == PASS )
|
||||
{
|
||||
evhttp_connection_set_timeout(event.req->evcon, event.timeout);
|
||||
|
||||
/* Default to retry for both blocking and non-blocking command */
|
||||
event.status = RETRY ;
|
||||
event.log_prefix = event.hostname ;
|
||||
event.log_prefix.append (" ");
|
||||
event.log_prefix.append (event.service) ;
|
||||
event.log_prefix.append (" ");
|
||||
event.log_prefix.append (event.operation) ;
|
||||
jlog2 ("%s Requested (blocking) (to:%d)\n", event.log_prefix.c_str(), event.timeout);
|
||||
|
||||
/* Send the message with timeout */
|
||||
event_base_dispatch(event.base);
|
||||
|
||||
httpUtil_free_conn ( event );
|
||||
httpUtil_free_base ( event );
|
||||
|
||||
return(event.status) ;
|
||||
}
|
||||
elog ("%s Call to 'evhttp_make_request' failed (rc:%d)\n",
|
||||
event.hostname.c_str(), rc);
|
||||
|
||||
return (FAIL_MAKE_REQUEST);
|
||||
}
|
32
mtce-guest/src/guestHttpUtil.h
Normal file
32
mtce-guest/src/guestHttpUtil.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef __INCLUDE_GUESTHTTPUTIL_H__
|
||||
#define __INCLUDE_GUESTHTTPUTIL_H__
|
||||
/*
|
||||
* Copyright (c) 2013, 2015 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Wind River CGTS Platform Controller Maintenance ...
|
||||
*
|
||||
* libevent HTTP support utilities and control structure support header
|
||||
*/
|
||||
|
||||
#include <iostream> /* for ... string */
|
||||
#include <evhttp.h> /* for ... http libevent client */
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "guestClass.h" /* for ... maintenance class nodeLinkClass */
|
||||
#include "httpUtil.h" /* for ... common http utilities */
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
void guestHttpUtil_init ( void );
|
||||
void guestHttpUtil_fini ( void );
|
||||
int guestHttpUtil_status ( libEvent & event );
|
||||
int guestHttpUtil_api_req ( libEvent & event );
|
||||
|
||||
#endif /* __INCLUDE_GUESTHTTPUTIL_H__ */
|
764
mtce-guest/src/guestInstClass.cpp
Normal file
764
mtce-guest/src/guestInstClass.cpp
Normal file
@ -0,0 +1,764 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2016 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Wind River CGTS Platform Guest Services "Instances Base Class"
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "nodeBase.h" /* for ... common definitions */
|
||||
#include "nodeEvent.h" /* for ... set_inotify_watch_file */
|
||||
#include "nodeTimers.h" /* for ... mtcTimer */
|
||||
#include "guestBase.h" /* for ... instInfo */
|
||||
#include "guestUtil.h" /* for ... guestUtil_inst_init */
|
||||
#include "guestInstClass.h" /* for ... get_inst */
|
||||
#include "guestSvrUtil.h" /* for ... hb_get_state_name */
|
||||
|
||||
/**< constructor */
|
||||
guestInstClass::guestInstClass()
|
||||
{
|
||||
inst_head = NULL ;
|
||||
inst_tail = NULL ;
|
||||
|
||||
memory_allocs = 0 ;
|
||||
memory_used = 0 ;
|
||||
instances = 0 ;
|
||||
|
||||
for ( int i = 0 ; i < MAX_INSTANCES ; i++ )
|
||||
{
|
||||
inst_ptrs[i] = NULL ;
|
||||
}
|
||||
|
||||
fsm_exit = false ;
|
||||
reporting = true ;
|
||||
return ;
|
||||
}
|
||||
|
||||
/**< destructor */
|
||||
guestInstClass::~guestInstClass()
|
||||
{
|
||||
inst * inst_ptr = inst_head ;
|
||||
inst * temp_ptr = inst_ptr ;
|
||||
while ( inst_ptr != NULL )
|
||||
{
|
||||
temp_ptr = inst_ptr ;
|
||||
inst_ptr = inst_ptr->next ;
|
||||
delInst (temp_ptr);
|
||||
}
|
||||
if ( memory_used != 0 )
|
||||
{
|
||||
elog ( "Apparent Memory Leak - Allocs:%d and Bytes:%d\n",
|
||||
memory_allocs, memory_used );
|
||||
}
|
||||
else
|
||||
{
|
||||
dlog ( "No Memory Leaks\n\n");
|
||||
}
|
||||
return ;
|
||||
}
|
||||
|
||||
void guestInstClass::guest_fsm_run ( void )
|
||||
{
|
||||
fsm_run ();
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate new instance and tack it on the end of the instance list
|
||||
*/
|
||||
struct guestInstClass::inst* guestInstClass::addInst ( string uuid )
|
||||
{
|
||||
if ( uuid.length() != UUID_LEN )
|
||||
{
|
||||
elog ("invalid instance uuid ; cannot add %s\n", uuid.c_str());
|
||||
return static_cast<struct inst *>(NULL);
|
||||
}
|
||||
|
||||
/* verify instance is not already provisioned */
|
||||
struct inst * inst_ptr = guestInstClass::getInst ( uuid );
|
||||
if ( inst_ptr )
|
||||
{
|
||||
if ( guestInstClass::remInst ( uuid ) )
|
||||
{
|
||||
/* Should never get here but if we do then */
|
||||
/* something is seriously wrong */
|
||||
elog ("%s unable to remove instance during reprovision\n",
|
||||
log_prefix(&inst_ptr->instance).c_str());
|
||||
return static_cast<struct inst *>(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* allocate memory for new instance */
|
||||
inst_ptr = guestInstClass::newInst ();
|
||||
if( inst_ptr == NULL )
|
||||
{
|
||||
elog ( "failed to allocate memory for new instance\n" );
|
||||
return static_cast<struct inst *>(NULL);
|
||||
}
|
||||
|
||||
guestUtil_inst_init ( &inst_ptr->instance );
|
||||
|
||||
/* Init the new instance */
|
||||
inst_ptr->instance.uuid = uuid ;
|
||||
inst_ptr->query_flag = false ;
|
||||
inst_ptr->instance.connect_wait_in_secs = DEFAULT_CONNECT_WAIT ;
|
||||
|
||||
/* Init instance's connect and monitor timers */
|
||||
/* Assign the timer the instance's name */
|
||||
mtcTimer_init ( inst_ptr->reconnect_timer, uuid );
|
||||
mtcTimer_init ( inst_ptr->connect_timer, uuid );
|
||||
mtcTimer_init ( inst_ptr->monitor_timer, uuid );
|
||||
mtcTimer_init ( inst_ptr->init_timer, uuid );
|
||||
mtcTimer_init ( inst_ptr->vote_timer, uuid );
|
||||
|
||||
inst_ptr->action = FSM_ACTION__NONE ;
|
||||
|
||||
inst_ptr->connectStage = INST_CONNECT__START ;
|
||||
inst_ptr->monitorStage = INST_MONITOR__STEADY ;
|
||||
inst_ptr->messageStage = INST_MESSAGE__RECEIVE ;
|
||||
|
||||
/* If the instance list is empty add it to the head */
|
||||
if( inst_head == NULL )
|
||||
{
|
||||
inst_head = inst_ptr ;
|
||||
inst_tail = inst_ptr ;
|
||||
inst_ptr->prev = NULL ;
|
||||
inst_ptr->next = NULL ;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* link the new_instance to the tail of the inst_list
|
||||
* then mark the next field as the end of the inst_list
|
||||
* adjust tail to point to the last instance
|
||||
*/
|
||||
inst_tail->next = inst_ptr ;
|
||||
inst_ptr->prev = inst_tail ;
|
||||
inst_ptr->next = NULL ;
|
||||
inst_tail = inst_ptr ;
|
||||
}
|
||||
|
||||
instances++ ;
|
||||
ilog ("%s added as instance %d\n", log_prefix(&inst_ptr->instance).c_str(), instances);
|
||||
return inst_ptr ;
|
||||
}
|
||||
|
||||
/* Remove an instance from the linked list of instances - may require splice action */
|
||||
int guestInstClass::remInst( string uuid )
|
||||
{
|
||||
if ( uuid.empty() )
|
||||
return -ENODEV ;
|
||||
|
||||
if ( inst_head == NULL )
|
||||
return -ENXIO ;
|
||||
|
||||
struct inst * inst_ptr = getInst ( uuid );
|
||||
|
||||
if ( inst_ptr == NULL )
|
||||
return -EFAULT ;
|
||||
|
||||
stop_instance_timers ( inst_ptr );
|
||||
|
||||
/* Close the channel if it is open */
|
||||
guestUtil_close_channel ( &inst_ptr->instance );
|
||||
|
||||
/* If the instance is the head instance */
|
||||
if ( inst_ptr == inst_head )
|
||||
{
|
||||
/* only one instance in the list case */
|
||||
if ( inst_head == inst_tail )
|
||||
{
|
||||
dlog2 ("Single Inst -> Head Case\n");
|
||||
inst_head = NULL ;
|
||||
inst_tail = NULL ;
|
||||
}
|
||||
else
|
||||
{
|
||||
dlog2 ("Multiple Insts -> Head Case\n");
|
||||
inst_head = inst_head->next ;
|
||||
inst_head->prev = NULL ;
|
||||
}
|
||||
}
|
||||
/* if not head but tail then there must be more than one
|
||||
* instance in the list so go ahead and chop the tail.
|
||||
*/
|
||||
else if ( inst_ptr == inst_tail )
|
||||
{
|
||||
dlog2 ("Multiple Inst -> Tail Case\n");
|
||||
inst_tail = inst_tail->prev ;
|
||||
inst_tail->next = NULL ;
|
||||
}
|
||||
else
|
||||
{
|
||||
dlog2 ("Multiple Inst -> Full Splice Out\n");
|
||||
inst_ptr->prev->next = inst_ptr->next ;
|
||||
inst_ptr->next->prev = inst_ptr->prev ;
|
||||
}
|
||||
delInst ( inst_ptr );
|
||||
instances-- ;
|
||||
|
||||
if ( instances == 0 )
|
||||
ilog ("no instances to monitor\n");
|
||||
|
||||
return (PASS) ;
|
||||
}
|
||||
|
||||
/* Perform a linked list search for the instance matching the instance name */
|
||||
struct guestInstClass::inst* guestInstClass::getInst ( string chan_or_uuid )
|
||||
{
|
||||
struct inst * inst_ptr = static_cast<struct inst *>(NULL) ;
|
||||
|
||||
/* check for empty list condition */
|
||||
if ( inst_head )
|
||||
{
|
||||
for ( inst_ptr = inst_head ; inst_ptr != NULL ; inst_ptr = inst_ptr->next )
|
||||
{
|
||||
if ( !inst_ptr->instance.uuid.compare (chan_or_uuid) )
|
||||
{
|
||||
return inst_ptr ;
|
||||
}
|
||||
if ( !inst_ptr->instance.chan.compare (chan_or_uuid) )
|
||||
{
|
||||
return inst_ptr ;
|
||||
}
|
||||
|
||||
if (( inst_ptr->next == NULL ) || ( inst_ptr == inst_tail ))
|
||||
break ;
|
||||
}
|
||||
}
|
||||
return static_cast<struct inst *>(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocates memory for a new instance and stores its address in inst_ptrs
|
||||
*
|
||||
* @param void
|
||||
* @return pointer to the newly allocted instance memory
|
||||
*/
|
||||
struct guestInstClass::inst * guestInstClass::newInst ( void )
|
||||
{
|
||||
struct guestInstClass::inst * temp_inst_ptr = NULL ;
|
||||
|
||||
if ( memory_allocs == 0 )
|
||||
{
|
||||
memset ( inst_ptrs, 0 , sizeof(struct inst *)*MAX_INSTANCES);
|
||||
}
|
||||
|
||||
// find an empty spot
|
||||
for ( int i = 0 ; i < MAX_INSTANCES ; i++ )
|
||||
{
|
||||
if ( inst_ptrs[i] == NULL )
|
||||
{
|
||||
inst_ptrs[i] = temp_inst_ptr = new inst ;
|
||||
memory_allocs++ ;
|
||||
memory_used += sizeof (struct guestInstClass::inst);
|
||||
|
||||
return temp_inst_ptr ;
|
||||
}
|
||||
}
|
||||
elog ( "failed to store new instance pointer address\n" );
|
||||
return temp_inst_ptr ;
|
||||
}
|
||||
|
||||
/* Frees the memory of a pre-allocated instance and removes
|
||||
* it from the inst_ptrs list.
|
||||
*
|
||||
* @param instance * pointer to the instance memory address to be freed
|
||||
* @return int return code { PASS or -EINVAL }
|
||||
*/
|
||||
int guestInstClass::delInst ( struct guestInstClass::inst * inst_ptr )
|
||||
{
|
||||
if ( memory_allocs > 0 )
|
||||
{
|
||||
for ( int i = 0 ; i < MAX_INSTANCES ; i++ )
|
||||
{
|
||||
if ( inst_ptrs[i] == inst_ptr )
|
||||
{
|
||||
delete inst_ptr ;
|
||||
inst_ptrs[i] = NULL ;
|
||||
memory_allocs-- ;
|
||||
memory_used -= sizeof (struct guestInstClass::inst);
|
||||
return PASS ;
|
||||
}
|
||||
}
|
||||
elog ( "unable to validate memory address being freed\n" );
|
||||
}
|
||||
else
|
||||
elog ( "free memory called when there is no memory to free\n" );
|
||||
|
||||
return -EINVAL ;
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
* P U B L I C I N T E R F A C E S
|
||||
**************************************************************************************/
|
||||
|
||||
/* Add an instance based on its uuid.
|
||||
* If the instance already exists then update its info */
|
||||
int guestInstClass::add_inst ( string uuid , instInfo & instance )
|
||||
{
|
||||
int rc = FAIL ;
|
||||
|
||||
struct guestInstClass::inst * inst_ptr = getInst(uuid);
|
||||
if ( inst_ptr )
|
||||
{
|
||||
ilog ("********************************************************\n");
|
||||
ilog ("%s Already provisioned - TODO: Create copy constructor \n", uuid.c_str());
|
||||
ilog ("********************************************************\n");
|
||||
|
||||
/* Send back a retry in case the add needs to be converted to a modify */
|
||||
rc = PASS ;
|
||||
}
|
||||
/* Otherwise add it as a new instance */
|
||||
else
|
||||
{
|
||||
if ( uuid.length() != UUID_LEN )
|
||||
{
|
||||
elog ("invalid uuid %s\n", uuid.c_str());
|
||||
return (FAIL_INVALID_UUID);
|
||||
}
|
||||
|
||||
inst_ptr = guestInstClass::addInst(uuid);
|
||||
if ( inst_ptr )
|
||||
{
|
||||
rc = PASS ;
|
||||
}
|
||||
else
|
||||
{
|
||||
elog ("failed to add instance '%s'\n", uuid.c_str());
|
||||
rc = FAIL_NULL_POINTER ;
|
||||
}
|
||||
}
|
||||
|
||||
if ( rc == PASS )
|
||||
{
|
||||
inst_ptr->heartbeat_count = 0 ;
|
||||
|
||||
inst_ptr->mismatch_count = 0 ;
|
||||
|
||||
/* TODO: This needs to be a complete copy - Need copy constructor */
|
||||
inst_ptr->instance.heartbeat.failures = 0 ;
|
||||
inst_ptr->instance.heartbeat.failed = false ;
|
||||
inst_ptr->instance.heartbeat.reporting = instance.heartbeat.reporting ;
|
||||
inst_ptr->instance.heartbeat.provisioned = instance.heartbeat.provisioned ;
|
||||
inst_ptr->instance.heartbeat.state = instance.heartbeat.state ;
|
||||
inst_ptr->instance.hbState = hbs_server_waiting_init ;
|
||||
inst_ptr->instance.vnState = hbs_server_waiting_init ;
|
||||
|
||||
inst_ptr->instance.name_log_prefix = "" ;
|
||||
inst_ptr->instance.uuid_log_prefix = "" ;
|
||||
|
||||
inst_ptr->instance.name = instance.name ;
|
||||
inst_ptr->instance.inst = instance.inst ;
|
||||
inst_ptr->instance.connected = instance.connected ;
|
||||
inst_ptr->instance.heartbeating = instance.heartbeating ;
|
||||
inst_ptr->instance.chan_fd = instance.chan_fd ;
|
||||
inst_ptr->instance.chan_ok = instance.chan_ok ;
|
||||
|
||||
inst_ptr->instance.corrective_action = instance.corrective_action ;
|
||||
inst_ptr->instance.heartbeat_interval_ms = instance.heartbeat_interval_ms ;
|
||||
|
||||
inst_ptr->instance.vote_secs = instance.vote_secs ;
|
||||
inst_ptr->instance.shutdown_notice_secs = instance.shutdown_notice_secs ;
|
||||
inst_ptr->instance.suspend_notice_secs = instance.suspend_notice_secs ;
|
||||
inst_ptr->instance.resume_notice_secs = instance.resume_notice_secs ;
|
||||
inst_ptr->instance.restart_secs = instance.restart_secs ;
|
||||
|
||||
/* Update the channel */
|
||||
if ( instance.chan.length() > UUID_LEN )
|
||||
inst_ptr->instance.chan = instance.chan ;
|
||||
}
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : del_inst
|
||||
*
|
||||
* Purpose : Delete an instance from the linked list
|
||||
*
|
||||
*****************************************************************************/
|
||||
int guestInstClass::del_inst ( string uuid )
|
||||
{
|
||||
int rc = FAIL ;
|
||||
if ( ! uuid.empty() )
|
||||
{
|
||||
/* free memory */
|
||||
rc = remInst ( uuid );
|
||||
}
|
||||
return ( rc );
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : qry_inst
|
||||
*
|
||||
* Purpose : Send instance info to the guestAgent
|
||||
*
|
||||
*****************************************************************************/
|
||||
int guestInstClass::qry_inst ( )
|
||||
{
|
||||
return ( guestAgent_qry_handler ());
|
||||
}
|
||||
|
||||
void guestInstClass::stop_instance_timers ( struct guestInstClass::inst * inst_ptr )
|
||||
{
|
||||
/* Free the mtc timer if in use */
|
||||
if ( inst_ptr->reconnect_timer.tid )
|
||||
{
|
||||
mtcTimer_stop ( inst_ptr->reconnect_timer );
|
||||
inst_ptr->reconnect_timer.ring = false ;
|
||||
inst_ptr->reconnect_timer.tid = NULL ;
|
||||
}
|
||||
/* Free the connect timer if in use */
|
||||
if ( inst_ptr->connect_timer.tid )
|
||||
{
|
||||
mtcTimer_stop ( inst_ptr->connect_timer );
|
||||
inst_ptr->connect_timer.ring = false ;
|
||||
inst_ptr->connect_timer.tid = NULL ;
|
||||
}
|
||||
/* Free the monitor timer if in use */
|
||||
if ( inst_ptr->monitor_timer.tid )
|
||||
{
|
||||
mtcTimer_stop ( inst_ptr->monitor_timer );
|
||||
inst_ptr->monitor_timer.ring = false ;
|
||||
inst_ptr->monitor_timer.tid = NULL ;
|
||||
}
|
||||
/* Free the init timer if in use */
|
||||
if ( inst_ptr->init_timer.tid )
|
||||
{
|
||||
mtcTimer_stop ( inst_ptr->init_timer );
|
||||
inst_ptr->init_timer.ring = false ;
|
||||
inst_ptr->init_timer.tid = NULL ;
|
||||
}
|
||||
/* Free the vote timer if in use */
|
||||
if ( inst_ptr->vote_timer.tid )
|
||||
{
|
||||
mtcTimer_stop ( inst_ptr->vote_timer );
|
||||
inst_ptr->vote_timer.ring = false ;
|
||||
inst_ptr->vote_timer.tid = NULL ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void guestInstClass::free_instance_resources ( void )
|
||||
{
|
||||
/* check for empty list condition */
|
||||
if ( inst_head )
|
||||
{
|
||||
for ( struct inst * inst_ptr = inst_head ; ; inst_ptr = inst_ptr->next )
|
||||
{
|
||||
if ( inst_ptr->instance.chan_fd )
|
||||
{
|
||||
ilog ("%s closing fd %d for uuid %s\n",
|
||||
log_prefix(&inst_ptr->instance).c_str(),
|
||||
inst_ptr->instance.chan_fd,
|
||||
inst_ptr->instance.uuid.c_str());
|
||||
|
||||
close ( inst_ptr->instance.chan_fd );
|
||||
}
|
||||
stop_instance_timers ( inst_ptr );
|
||||
|
||||
if (( inst_ptr->next == NULL ) || ( inst_ptr == inst_tail ))
|
||||
break ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/** FSM Control Utilities */
|
||||
/****************************************************************************/
|
||||
|
||||
void guestInstClass::reconnect_start ( const char * uuid_ptr )
|
||||
{
|
||||
string uuid = uuid_ptr ;
|
||||
if ( uuid.length() != UUID_LEN )
|
||||
{
|
||||
elog ("invalid uuid %s (uuid:%ld)\n", uuid.c_str(), uuid.length());
|
||||
return ;
|
||||
}
|
||||
|
||||
struct guestInstClass::inst * inst_ptr = guestInstClass::getInst(uuid);
|
||||
if ( inst_ptr )
|
||||
{
|
||||
guestUtil_close_channel ( &inst_ptr->instance );
|
||||
}
|
||||
else
|
||||
{
|
||||
inst_ptr = guestInstClass::addInst(uuid);
|
||||
}
|
||||
|
||||
if ( inst_ptr )
|
||||
{
|
||||
instInfo * instInfo_ptr = &inst_ptr->instance ;
|
||||
if ( instInfo_ptr->fd_namespace.size() )
|
||||
{
|
||||
/* Setup inotify to watch for new instance serial IO channel creations */
|
||||
if ( set_inotify_watch_file ( instInfo_ptr->fd_namespace.data(),
|
||||
instInfo_ptr->inotify_file_fd,
|
||||
instInfo_ptr->inotify_file_wd))
|
||||
{
|
||||
elog ("%s failed to setup 'inotify' on %s\n",
|
||||
log_prefix(instInfo_ptr).c_str(),
|
||||
instInfo_ptr->fd_namespace.c_str());
|
||||
}
|
||||
}
|
||||
ilog ("%s reconnecting ... %s\n", log_prefix(instInfo_ptr).c_str(),
|
||||
instInfo_ptr->connected ? " CONNECTED" : "" );
|
||||
|
||||
if ( inst_ptr->connect_timer.tid )
|
||||
mtcTimer_stop ( inst_ptr->connect_timer );
|
||||
|
||||
inst_ptr->action = FSM_ACTION__CONNECT ;
|
||||
inst_ptr->connectStage = INST_CONNECT__START ;
|
||||
|
||||
// mtcTimer_start ( inst_ptr->connect_timer, guestTimer_handler, inst_ptr->instance.connect_wait_in_secs );
|
||||
|
||||
//ilog ("%s connect attempt in %d seconds\n",
|
||||
// log_prefix(&inst_ptr->instance).c_str(), inst_ptr->instance.connect_wait_in_secs);
|
||||
instInfo_ptr->connecting = true ;
|
||||
}
|
||||
else
|
||||
{
|
||||
elog ("%s failed to find or add instance\n", uuid.c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/** Inst Class Setter / Getters */
|
||||
/****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : get_inst
|
||||
*
|
||||
* Purpose : Return a pointer to the instance for a specified uuid
|
||||
*
|
||||
*****************************************************************************/
|
||||
instInfo * guestInstClass::get_inst ( string uuid )
|
||||
{
|
||||
struct guestInstClass::inst * inst_ptr = guestInstClass::getInst(uuid);
|
||||
if ( inst_ptr )
|
||||
{
|
||||
return (&inst_ptr->instance );
|
||||
}
|
||||
return static_cast<instInfo *>(NULL);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : getInst_timer
|
||||
*
|
||||
* Purpose : Return a pointer to the instance that contains the timer for
|
||||
* the specified timer ID.
|
||||
*
|
||||
*****************************************************************************/
|
||||
struct guestInstClass::inst * guestInstClass::getInst_timer ( timer_t tid, int timer_id )
|
||||
{
|
||||
if ( tid != NULL )
|
||||
{
|
||||
if ( inst_head )
|
||||
{
|
||||
struct inst * inst_ptr ;
|
||||
for ( inst_ptr = inst_head ; inst_ptr != NULL ; inst_ptr = inst_ptr->next )
|
||||
{
|
||||
if (( timer_id == INST_TIMER_MONITOR ) && (inst_ptr->monitor_timer.tid == tid ))
|
||||
{
|
||||
return inst_ptr ;
|
||||
}
|
||||
else if (( timer_id == INST_TIMER_CONNECT ) && (inst_ptr->connect_timer.tid == tid ))
|
||||
{
|
||||
return inst_ptr ;
|
||||
}
|
||||
else if (( timer_id == INST_TIMER_VOTE ) && ( inst_ptr->vote_timer.tid == tid ))
|
||||
{
|
||||
return inst_ptr ;
|
||||
}
|
||||
else if (( timer_id == INST_TIMER_INIT ) && ( inst_ptr->init_timer.tid == tid ))
|
||||
{
|
||||
return inst_ptr ;
|
||||
}
|
||||
else if (( timer_id == INST_TIMER_RECONNECT ) && ( inst_ptr->reconnect_timer.tid == tid ))
|
||||
{
|
||||
return inst_ptr ;
|
||||
}
|
||||
|
||||
if (( inst_ptr->next == NULL ) || ( inst_ptr == inst_tail ))
|
||||
break ;
|
||||
}
|
||||
}
|
||||
}
|
||||
return static_cast<struct inst *>(NULL);
|
||||
}
|
||||
|
||||
/* Get an instance's heartbeat fault reporting state */
|
||||
bool guestInstClass::get_reporting_state ( string uuid )
|
||||
{
|
||||
guestInstClass::inst * inst_ptr = guestInstClass::getInst ( uuid );
|
||||
if ( inst_ptr )
|
||||
{
|
||||
return ( inst_ptr->instance.heartbeat.reporting );
|
||||
}
|
||||
else
|
||||
{
|
||||
wlog ("uuid not found '%s'\n", uuid.c_str());
|
||||
}
|
||||
return ( false );
|
||||
}
|
||||
|
||||
/* Set an instances heartbeat fault reporting state */
|
||||
int guestInstClass::set_reporting_state( string uuid, bool reporting )
|
||||
{
|
||||
guestInstClass::inst * inst_ptr = guestInstClass::getInst ( uuid );
|
||||
if ( inst_ptr )
|
||||
{
|
||||
inst_ptr->instance.heartbeat.reporting = reporting ;
|
||||
}
|
||||
else
|
||||
{
|
||||
wlog ("uuid not found '%s'\n", uuid.c_str());
|
||||
return (FAIL_NOT_FOUND) ;
|
||||
}
|
||||
return (PASS);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : print_all_instances
|
||||
*
|
||||
* Purpose: Print a summary of the instances that are currently provisioned
|
||||
*
|
||||
*****************************************************************************/
|
||||
void guestInstClass::print_all_instances ( void )
|
||||
{
|
||||
bool found = false;
|
||||
int i = 0 ;
|
||||
if ( inst_head )
|
||||
{
|
||||
struct inst * inst_ptr ;
|
||||
for ( inst_ptr = inst_head ; inst_ptr != NULL ; inst_ptr = inst_ptr->next )
|
||||
{
|
||||
ilog ("%2d %s Heartbeat: Notify:%c Failures:%d\n", i,
|
||||
log_prefix(&inst_ptr->instance).c_str(),
|
||||
inst_ptr->instance.heartbeat.reporting ? 'Y':'n',
|
||||
inst_ptr->instance.heartbeat.failures);
|
||||
found = true ;
|
||||
i++ ;
|
||||
if (( inst_ptr->next == NULL ) || ( inst_ptr == inst_tail ))
|
||||
break ;
|
||||
}
|
||||
}
|
||||
|
||||
if ( found == false )
|
||||
{
|
||||
ilog ("no instances provisioned\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : print_instances (private)
|
||||
*
|
||||
*****************************************************************************/
|
||||
void guestInstClass::print_instances ( void )
|
||||
{
|
||||
print_all_instances();
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Memory Dump Stuff *
|
||||
*****************************************************************************/
|
||||
void guestInstClass::print_node_info ( void )
|
||||
{
|
||||
fflush (stdout);
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
void guestInstClass::mem_log_info ( void )
|
||||
{
|
||||
char str[MAX_MEM_LOG_DATA] ;
|
||||
snprintf (&str[0], MAX_MEM_LOG_DATA, "Instances:%d Allocs:%d Memory:%d\n", instances, memory_allocs, memory_used );
|
||||
mem_log (str);
|
||||
}
|
||||
|
||||
void mem_log_delimit_host ( void )
|
||||
{
|
||||
char str[MAX_MEM_LOG_DATA] ;
|
||||
snprintf (&str[0], MAX_MEM_LOG_DATA, "-------------------------------------------------------------\n");
|
||||
mem_log (str);
|
||||
}
|
||||
|
||||
void guestInstClass::mem_log_inst_info ( void )
|
||||
{
|
||||
char str[MAX_MEM_LOG_DATA] ;
|
||||
|
||||
struct inst * inst_ptr = static_cast<struct inst *>(NULL) ;
|
||||
|
||||
for ( inst_ptr = inst_head ; inst_ptr != NULL ; inst_ptr = inst_ptr->next )
|
||||
{
|
||||
snprintf (&str[0], MAX_MEM_LOG_DATA, "Name : %s %s (%s)\n",
|
||||
inst_ptr->instance.name.data(),
|
||||
inst_ptr->instance.uuid.data(),
|
||||
inst_ptr->instance.inst.data());
|
||||
mem_log (str);
|
||||
|
||||
snprintf (&str[0], MAX_MEM_LOG_DATA, "Action: %8d Connect:%2d Message:%2d Delay:%d secs\n",
|
||||
inst_ptr->action,
|
||||
inst_ptr->connectStage,
|
||||
inst_ptr->messageStage,
|
||||
inst_ptr->instance.connect_wait_in_secs);
|
||||
mem_log (str);
|
||||
|
||||
snprintf (&str[0], MAX_MEM_LOG_DATA, "State : Reporting: %c Failures: %d Failed: %c\n",
|
||||
inst_ptr->instance.heartbeat.reporting ? 'Y' : 'n',
|
||||
inst_ptr->instance.heartbeat.failures,
|
||||
inst_ptr->instance.heartbeat.failed ? 'Y' : 'n' );
|
||||
mem_log (str);
|
||||
|
||||
snprintf (&str[0], MAX_MEM_LOG_DATA, "Setup : Select :%2d Channel OK: %c hbState:%s vnState:%s\n",
|
||||
inst_ptr->instance.chan_fd,
|
||||
inst_ptr->instance.chan_ok ? 'Y' : 'n' ,
|
||||
hb_get_state_name(inst_ptr->instance.hbState),
|
||||
hb_get_state_name(inst_ptr->instance.vnState));
|
||||
mem_log (str);
|
||||
|
||||
snprintf (&str[0], MAX_MEM_LOG_DATA, "Oper : Connected: %c Heartbeating: %c\n",
|
||||
inst_ptr->instance.connected ? 'Y' : 'n',
|
||||
inst_ptr->instance.heartbeating ? 'Y' : 'n');
|
||||
mem_log (str);
|
||||
|
||||
mem_log_delimit_host();
|
||||
|
||||
/* exit if this happens to be the last one in the list */
|
||||
if (( inst_ptr->next == NULL ) || ( inst_ptr == inst_tail ))
|
||||
break ;
|
||||
}
|
||||
if ( inst_head == NULL )
|
||||
{
|
||||
snprintf (&str[0], MAX_MEM_LOG_DATA, "no instances\n");
|
||||
mem_log (str);
|
||||
}
|
||||
}
|
||||
|
||||
void guestInstClass::memDumpAllState ( void )
|
||||
{
|
||||
mem_log_info ( );
|
||||
mem_log_delimit_host ();
|
||||
mem_log_inst_info ();
|
||||
}
|
230
mtce-guest/src/guestInstClass.h
Normal file
230
mtce-guest/src/guestInstClass.h
Normal file
@ -0,0 +1,230 @@
|
||||
#ifndef __INCLUDE_INSTBASECLASS_H__
|
||||
#define __INCLUDE_INSTBASECLASS_H__
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013-2018 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Wind River CGTS Platform Guest Services "Instances Base Class Header"
|
||||
*/
|
||||
|
||||
#include <json-c/json.h>
|
||||
#include "guestBase.h" /* for ... instInfo */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FSM_ACTION__NONE,
|
||||
FSM_ACTION__CONNECT,
|
||||
FSM_ACTION__LAST
|
||||
|
||||
} guest_fsmActions_enum ;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
INST_CONNECT__START = 1,
|
||||
INST_CONNECT__WAIT = 2,
|
||||
INST_CONNECT__RETRY = 3,
|
||||
INST_CONNECT__DONE = 4,
|
||||
INST_CONNECT__STAGES = 5
|
||||
} guest_connectStages_enum ;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
INST_MONITOR__STEADY = 0,
|
||||
INST_MONITOR__DELAY = 2,
|
||||
INST_MONITOR__FAILURE = 1,
|
||||
} guest_monitorStages_enum ;
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
INST_MESSAGE__RECEIVE = 0,
|
||||
INST_MESSAGE__SEND_INIT_ACK = 1,
|
||||
INST_MESSAGE__RESP_WAIT = 2, /* Waiting for heartbeat challenge response */
|
||||
INST_MESSAGE__SEND_WAIT = 3, /* Waiting for period to expire for challenge resend */
|
||||
INST_MESSAGE__TRANSMIT = 4,
|
||||
INST_MESSAGE__STALL = 5
|
||||
} guest_messageStages_enum ;
|
||||
|
||||
class guestInstClass
|
||||
{
|
||||
private:
|
||||
struct inst {
|
||||
|
||||
/** Pointer to the previous / next host in the list */
|
||||
struct inst * prev;
|
||||
struct inst * next;
|
||||
|
||||
/* Instance info */
|
||||
instInfo instance ;
|
||||
|
||||
/**
|
||||
* Top level gate for the host.
|
||||
* If false then reporting for all instances are off.
|
||||
*/
|
||||
// bool reporting;
|
||||
|
||||
bool query_flag ;
|
||||
|
||||
#define INST_TIMER_MONITOR (0)
|
||||
#define INST_TIMER_CONNECT (1)
|
||||
#define INST_TIMER_RECONNECT (2)
|
||||
#define INST_TIMER_INIT (3)
|
||||
#define INST_TIMER_VOTE (4)
|
||||
#define INST_TIMER_MAX (5)
|
||||
|
||||
// number of continuous reads for an instance to deal with
|
||||
// potential message burst
|
||||
#define INST_MSG_READ_COUNT 5
|
||||
|
||||
/** General Purpose instance timer */
|
||||
// struct mtc_timer timer;
|
||||
struct mtc_timer vote_timer;
|
||||
struct mtc_timer init_timer;
|
||||
struct mtc_timer monitor_timer;
|
||||
struct mtc_timer connect_timer;
|
||||
struct mtc_timer reconnect_timer;
|
||||
|
||||
|
||||
guest_connectStages_enum connectStage ;
|
||||
guest_messageStages_enum messageStage ;
|
||||
guest_monitorStages_enum monitorStage ;
|
||||
|
||||
guest_fsmActions_enum action ;
|
||||
|
||||
int monitor_handler_count ;
|
||||
int message_handler_count ;
|
||||
int connect_handler_count ;
|
||||
int mismatch_count ;
|
||||
int heartbeat_count ;
|
||||
|
||||
/* Message list for this instance*/
|
||||
list<struct json_object *> message_list ;
|
||||
};
|
||||
|
||||
struct inst * inst_head ; /**< Inst Linked List Head pointer */
|
||||
struct inst * inst_tail ; /**< Inst Linked List Tail pointer */
|
||||
|
||||
/** List of allocated host memory.
|
||||
*
|
||||
* An array of host pointers.
|
||||
*/
|
||||
inst * inst_ptrs[MAX_HOSTS] ;
|
||||
|
||||
/** A memory allocation counter.
|
||||
*
|
||||
* Should represent the number of hosts in the linked list.
|
||||
*/
|
||||
int memory_allocs ;
|
||||
|
||||
/** A memory used counter
|
||||
*
|
||||
* A variable storing the accumulated instance memory
|
||||
*/
|
||||
int memory_used ;
|
||||
|
||||
bool fsm_exit ;
|
||||
void fsm_run ( void );
|
||||
|
||||
struct guestInstClass::inst* newInst ( void );
|
||||
struct guestInstClass::inst* addInst ( string uuid );
|
||||
struct guestInstClass::inst* getInst ( string uuid );
|
||||
int remInst ( string uuid );
|
||||
int delInst ( struct guestInstClass::inst * inst_ptr );
|
||||
void readInst ( void );
|
||||
|
||||
void print_all_instances ( void );
|
||||
|
||||
void mem_log_inst_info ( void );
|
||||
|
||||
struct guestInstClass::inst* getInst_timer ( timer_t tid, int timer_id );
|
||||
|
||||
int message_handler ( struct guestInstClass::inst * inst_ptr );
|
||||
int connect_handler ( struct guestInstClass::inst * inst_ptr );
|
||||
int monitor_handler ( struct guestInstClass::inst * inst_ptr );
|
||||
|
||||
void start_monitor_timer ( struct guestInstClass::inst * inst_ptr );
|
||||
|
||||
/** Thus member function loops over all the insances and sends
|
||||
* a json string instances: [uuid:state],[uuid:state]...
|
||||
* back to the guestAgent. */
|
||||
int guestAgent_qry_handler ( void );
|
||||
|
||||
int send_challenge ( struct guestInstClass::inst * inst_ptr );
|
||||
|
||||
void manage_comm_loss ( void );
|
||||
|
||||
void mem_log_info ( void );
|
||||
void process_msg(json_object *jobj_msg, struct guestInstClass::inst * inst_ptr);
|
||||
void parser(char *buf, ssize_t len, json_tokener* tok, int newline_found, struct guestInstClass::inst * inst_ptr);
|
||||
void handle_virtio_serial_msg(char *buf, ssize_t len, json_tokener* tok, struct guestInstClass::inst * inst_ptr);
|
||||
|
||||
public:
|
||||
|
||||
guestInstClass(); /**< constructor */
|
||||
~guestInstClass(); /**< destructor */
|
||||
|
||||
bool reporting ;
|
||||
void print_instances ( void );
|
||||
|
||||
/** handle an expired timer */
|
||||
void timer_handler ( int sig, siginfo_t *si, void *uc);
|
||||
|
||||
struct mtc_timer search_timer;
|
||||
|
||||
int instances ;
|
||||
void guest_fsm_run ( void );
|
||||
|
||||
int qry_inst ( void );
|
||||
int add_inst ( string uuid, instInfo & instance );
|
||||
int mod_inst ( string uuid, instInfo & instance );
|
||||
int del_inst ( string uuid );
|
||||
instInfo * get_inst ( string uuid );
|
||||
|
||||
ssize_t write_inst ( instInfo * ptr, const char *message, size_t size);
|
||||
|
||||
void reconnect_start ( const char * uuid_ptr ) ; // string uuid );
|
||||
|
||||
void set_query_flag ( string uuid );
|
||||
bool get_query_flag ( string uuid );
|
||||
bool get_reporting_state( string uuid );
|
||||
int set_reporting_state( string uuid, bool enabled );
|
||||
|
||||
int send_vote_notify ( string uuid );
|
||||
int send_vote_notify_resp ( char * hostname, string uuid,
|
||||
string notification_type,
|
||||
string event_type,
|
||||
string vote_result,
|
||||
string reject_reason);
|
||||
|
||||
void send_client_msg_nack ( instInfo * instInfo_ptr,
|
||||
string log_err);
|
||||
void handle_parse_failure ( struct guestInstClass::inst * inst_ptr,
|
||||
const char *key,
|
||||
struct json_object *jobj_msg);
|
||||
|
||||
/* Called on controlle daemon exit */
|
||||
void free_instance_resources ( void );
|
||||
void stop_instance_timers ( struct guestInstClass::inst * inst_ptr );
|
||||
|
||||
/* For select dispatch */
|
||||
struct timeval waitd ;
|
||||
|
||||
fd_set inotify_readfds ;
|
||||
fd_set instance_readfds ;
|
||||
fd_set message_readfds ;
|
||||
|
||||
void memLogDelimit ( void ); /**< Debug log delimiter */
|
||||
void memDumpNodeState ( string uuid );
|
||||
void memDumpAllState ( void );
|
||||
void print_node_info ( void ); /**< Print node info banner */
|
||||
};
|
||||
|
||||
guestInstClass * get_instInv_ptr ( void );
|
||||
|
||||
#endif /* __INCLUDE_INSTBASECLASS_H__ */
|
580
mtce-guest/src/guestServer.cpp
Normal file
580
mtce-guest/src/guestServer.cpp
Normal file
@ -0,0 +1,580 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2016 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Wind River CGTS Platform Guest Heartbeat Server Daemon on Compute
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <netdb.h> /* for hostent */
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h> /* for close and usleep */
|
||||
#include <sched.h> /* for realtime scheduling api */
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "nodeBase.h"
|
||||
#include "daemon_ini.h" /* Ini Parser Header */
|
||||
#include "daemon_common.h" /* Common definitions and types for daemons */
|
||||
#include "daemon_option.h" /* Common options for daemons */
|
||||
#include "nodeUtil.h" /* for ... common utilities */
|
||||
#include "jsonUtil.h" /* for ... jason utilities */
|
||||
#include "nodeTimers.h" /* for ... maintenance timers */
|
||||
#include "nodeMacro.h" /* for ... CREATE_NONBLOCK_INET_UDP_RX_SOCKET */
|
||||
#include "nodeEvent.h" /* for ... set_inotify_watch, set_inotify_close */
|
||||
#include "guestBase.h"
|
||||
#include "guestUtil.h" /* for ... guestUtil_inst_init */
|
||||
#include "guestSvrUtil.h" /* for ... guestUtil_inotify_events */
|
||||
#include "guestVirtio.h" /* for ... virtio_channel_connect */
|
||||
#include "guestSvrMsg.h" /* for ... send_to_guestAgent */
|
||||
#include "guestInstClass.h"
|
||||
|
||||
/* Where to send events */
|
||||
string guestAgent_ip = "" ;
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* The daemon primary instance racking object.
|
||||
*
|
||||
* This object is a dynamically managed linked list of tracked insances
|
||||
*
|
||||
* @see guestInstClass Module control structure in guestInstClass.h
|
||||
*
|
||||
*****************************************************************************/
|
||||
guestInstClass instInv ;
|
||||
guestInstClass * get_instInv_ptr ( void ) { return(&instInv); }
|
||||
|
||||
|
||||
/* @see guestBase.h Module control structure
|
||||
* TODO: Consider obsoleting by moving into class */
|
||||
ctrl_type ctrl ;
|
||||
ctrl_type * get_ctrl_ptr ( void )
|
||||
{
|
||||
return(&ctrl);
|
||||
}
|
||||
|
||||
void daemon_sigchld_hdlr ( void )
|
||||
{
|
||||
; /* dlog("Received SIGCHLD ... no action\n"); */
|
||||
}
|
||||
|
||||
/**
|
||||
* Daemon Configuration Structure - The allocated struct
|
||||
* @see daemon_common.h for daemon_config_type struct format.
|
||||
*/
|
||||
static daemon_config_type guest_config ;
|
||||
daemon_config_type * daemon_get_cfg_ptr () { return &guest_config ; }
|
||||
|
||||
/* Cleanup exit handler */
|
||||
void daemon_exit ( void )
|
||||
{
|
||||
daemon_dump_info ();
|
||||
daemon_files_fini ();
|
||||
|
||||
/* Close the messaging sockets */
|
||||
if ( ctrl.sock.server_rx_sock )
|
||||
delete (ctrl.sock.server_rx_sock);
|
||||
|
||||
if ( ctrl.sock.server_tx_sock )
|
||||
delete (ctrl.sock.server_tx_sock);
|
||||
|
||||
if ( ctrl.sock.agent_rx_float_sock )
|
||||
delete (ctrl.sock.agent_rx_float_sock);
|
||||
|
||||
if ( ctrl.sock.agent_tx_sock )
|
||||
delete (ctrl.sock.agent_tx_sock);
|
||||
|
||||
/* Turn off inotify */
|
||||
set_inotify_close ( ctrl.inotify_dir_fd, ctrl.inotify_dir_wd );
|
||||
|
||||
instInv.free_instance_resources ();
|
||||
|
||||
fflush (stdout);
|
||||
fflush (stderr);
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
/** Client Config mask */
|
||||
#define CONFIG_MASK (CONFIG_CLIENT_RX_PORT |\
|
||||
CONFIG_AGENT_RX_PORT)
|
||||
|
||||
/* Startup config read */
|
||||
static int _config_handler ( void * user,
|
||||
const char * section,
|
||||
const char * name,
|
||||
const char * value)
|
||||
{
|
||||
daemon_config_type* config_ptr = (daemon_config_type*)user;
|
||||
|
||||
if (MATCH("agent", "rx_port"))
|
||||
{
|
||||
config_ptr->agent_rx_port = atoi(value);
|
||||
config_ptr->mask |= CONFIG_AGENT_RX_PORT ;
|
||||
}
|
||||
else if (MATCH("client", "rx_port"))
|
||||
{
|
||||
config_ptr->client_rx_port = atoi(value);
|
||||
config_ptr->mask |= CONFIG_CLIENT_RX_PORT ;
|
||||
}
|
||||
else if (MATCH("client", "hbs_pulse_period"))
|
||||
{
|
||||
config_ptr->hbs_pulse_period = atoi(value);
|
||||
}
|
||||
else if (MATCH("client", "hbs_failure_threshold"))
|
||||
{
|
||||
config_ptr->hbs_failure_threshold = atoi(value);
|
||||
}
|
||||
#ifdef WANT_REPORT_DELAY
|
||||
else if (MATCH("timeouts", "start_delay"))
|
||||
{
|
||||
config_ptr->start_delay = atoi(value);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
return (PASS);
|
||||
}
|
||||
return (FAIL);
|
||||
}
|
||||
|
||||
/* Read the guest.ini file and load agent */
|
||||
/* settings into the daemon configuration */
|
||||
int daemon_configure ( void )
|
||||
{
|
||||
int rc = FAIL ;
|
||||
|
||||
/* Read the ini */
|
||||
char config_fn[100] ;
|
||||
guest_config.mask = 0 ;
|
||||
sprintf ( &config_fn[0], "/etc/mtc/%s.ini", program_invocation_short_name );
|
||||
if (ini_parse(config_fn, _config_handler, &guest_config) < 0)
|
||||
{
|
||||
elog("Can't load '%s'\n", config_fn );
|
||||
return (FAIL_LOAD_INI);
|
||||
}
|
||||
|
||||
get_debug_options ( config_fn, &guest_config );
|
||||
|
||||
/* Verify loaded config against an expected mask
|
||||
* as an ini file fault detection method */
|
||||
if ( guest_config.mask != CONFIG_MASK )
|
||||
{
|
||||
elog ("Configuration load failed (%x)\n",
|
||||
(( -1 ^ guest_config.mask ) & CONFIG_MASK) );
|
||||
rc = FAIL_INI_CONFIG ;
|
||||
}
|
||||
else
|
||||
{
|
||||
guest_config.mgmnt_iface = daemon_get_iface_master ( guest_config.mgmnt_iface );
|
||||
ilog("Guest Agent : %s:%d\n", guest_config.mgmnt_iface, guest_config.client_rx_port );
|
||||
|
||||
// get_iface_macaddr ( guest_config.mgmnt_iface, my_macaddr );
|
||||
get_iface_address ( guest_config.mgmnt_iface, ctrl.address, true );
|
||||
get_hostname ( &ctrl.hostname[0], MAX_HOST_NAME_SIZE );
|
||||
|
||||
ilog("Report Thres: %d\n", guest_config.hbs_failure_threshold );
|
||||
#ifdef WANT_REPORT_DELAY
|
||||
ilog("Report Delay: %d sec\n", guest_config.start_delay );
|
||||
#endif
|
||||
ilog("Deflt Period: %d msec\n", guest_config.hbs_pulse_period );
|
||||
rc = PASS ;
|
||||
}
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
|
||||
/****************************/
|
||||
/* Initialization Utilities */
|
||||
/****************************/
|
||||
|
||||
/* Setup UDP messaging to the guestAgent. */
|
||||
int _socket_init ( void )
|
||||
{
|
||||
int rc = PASS ;
|
||||
|
||||
guestAgent_ip = getipbyname ( CONTROLLER );
|
||||
ilog ("ControllerIP: %s\n", guestAgent_ip.c_str());
|
||||
|
||||
/* Read the ports the socket struct */
|
||||
ctrl.sock.agent_rx_port = guest_config.agent_rx_port ;
|
||||
ctrl.sock.server_rx_port = guest_config.client_rx_port ;
|
||||
|
||||
/****************************/
|
||||
/* Setup the Receive Socket */
|
||||
/****************************/
|
||||
ctrl.sock.server_rx_sock = new msgClassRx(ctrl.address.c_str(), guest_config.client_rx_port, IPPROTO_UDP);
|
||||
rc = ctrl.sock.server_rx_sock->return_status;
|
||||
if ( rc )
|
||||
{
|
||||
elog ("Failed to setup 'guestAgent' receiver on port %d\n",
|
||||
ctrl.sock.server_rx_port );
|
||||
return (rc) ;
|
||||
}
|
||||
ctrl.sock.server_tx_sock = new msgClassTx(guestAgent_ip.c_str(), guest_config.agent_rx_port, IPPROTO_UDP, guest_config.mgmnt_iface);
|
||||
rc = ctrl.sock.server_tx_sock->return_status;
|
||||
if ( rc )
|
||||
{
|
||||
elog ("Failed to setup 'guestServer' transmiter\n" );
|
||||
return (rc) ;
|
||||
}
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/* The main heartbeat service loop */
|
||||
int daemon_init ( string iface, string nodeType_str )
|
||||
{
|
||||
int rc = PASS ;
|
||||
|
||||
ctrl.address.clear() ;
|
||||
ctrl.address_peer.clear();
|
||||
ctrl.nodetype = CGTS_NODE_NULL ;
|
||||
|
||||
/* Init the Inotify descriptors */
|
||||
ctrl.inotify_dir_fd = 0 ;
|
||||
ctrl.inotify_dir_wd = 0 ;
|
||||
|
||||
/* clear hostname */
|
||||
memset ( &ctrl.hostname[0], 0, MAX_HOST_NAME_SIZE );
|
||||
|
||||
/* Initialize socket construct and pointer to it */
|
||||
memset ( &ctrl.sock, 0, sizeof(ctrl.sock));
|
||||
|
||||
/* Assign interface to config */
|
||||
guest_config.mgmnt_iface = (char*)iface.data() ;
|
||||
|
||||
if ( (rc = daemon_files_init ( )) != PASS )
|
||||
{
|
||||
elog ("Pid, log or other files could not be opened (rc:%d)\n", rc );
|
||||
rc = FAIL_FILES_INIT ;
|
||||
}
|
||||
|
||||
/* convert node type to integer */
|
||||
ctrl.nodetype = get_host_function_mask ( nodeType_str ) ;
|
||||
ilog ("Node Type : %s (%d)\n", nodeType_str.c_str(), ctrl.nodetype );
|
||||
|
||||
/* Bind signal handlers */
|
||||
if ( daemon_signal_init () != PASS )
|
||||
{
|
||||
elog ("daemon_signal_init failed\n");
|
||||
return ( FAIL_SIGNAL_INIT );
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* There is no point continuing with init ; i.e. running daemon_configure,
|
||||
* initializing sockets and trying to query for an ip address until the
|
||||
* daemon's configuration requirements are met. Here we wait for those
|
||||
* flag files to be present before continuing.
|
||||
************************************************************************
|
||||
* Wait for /etc/platform/.initial_config_complete & /var/run/.goenabled */
|
||||
daemon_wait_for_file ( CONFIG_COMPLETE_FILE , 0);
|
||||
daemon_wait_for_file ( GOENABLED_MAIN_READY , 0);
|
||||
|
||||
/* Configure the client */
|
||||
if ( (rc = daemon_configure ()) != PASS )
|
||||
{
|
||||
elog ("Daemon service configuration failed (rc:%d)\n", rc );
|
||||
rc = FAIL_DAEMON_CONFIG ;
|
||||
}
|
||||
|
||||
/* Setup the heartbeat service messaging sockets */
|
||||
else if ( (rc = _socket_init ( )) != PASS )
|
||||
{
|
||||
elog ("socket initialization failed (rc:%d)\n", rc );
|
||||
rc = FAIL_SOCKET_INIT;
|
||||
}
|
||||
|
||||
/* Ignore this signal */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/*
|
||||
{ hostname" : "<hostname>" ,
|
||||
"instances" :
|
||||
[
|
||||
{ "channel" : "<channel>" , "services" :
|
||||
[
|
||||
{ "service":"heartbeat", "admin":"enabled", "oper":"enabled" , "avail":"available" }
|
||||
],
|
||||
"channel: : "<channel>" , "services" :
|
||||
[
|
||||
{ "service":"heartbeat", "admin":"enabled", "oper":"enabled" , "avail":"available"}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
int select_failure_count = 0 ;
|
||||
|
||||
void guestInstClass::manage_comm_loss ( void )
|
||||
{
|
||||
int rc ;
|
||||
|
||||
std::list<int> socks ;
|
||||
socks.clear();
|
||||
|
||||
waitd.tv_sec = 0;
|
||||
waitd.tv_usec = GUEST_SOCKET_TO;
|
||||
|
||||
/* Initialize the master fd_set */
|
||||
FD_ZERO(&inotify_readfds);
|
||||
|
||||
/* check for empty list condition */
|
||||
if ( inst_head )
|
||||
{
|
||||
for ( struct inst * inst_ptr = inst_head ; inst_ptr != NULL ; inst_ptr = inst_ptr->next )
|
||||
{
|
||||
if ( inst_ptr->instance.inotify_file_fd )
|
||||
{
|
||||
//ilog ("adding inotify_fd %d for %s to select list\n",
|
||||
// inst_ptr->instance.inotify_file_fd,
|
||||
// inst_ptr->instance.uuid.c_str());
|
||||
|
||||
socks.push_front ( inst_ptr->instance.inotify_file_fd );
|
||||
FD_SET ( inst_ptr->instance.inotify_file_fd, &inotify_readfds);
|
||||
}
|
||||
if (( inst_ptr->next == NULL ) || ( inst_ptr == inst_tail ))
|
||||
break ;
|
||||
}
|
||||
|
||||
/* if there are no sockets to monitor then just exit */
|
||||
if ( socks.empty() )
|
||||
return ;
|
||||
|
||||
/* Call select() and wait only up to SOCKET_WAIT */
|
||||
socks.sort();
|
||||
rc = select( socks.back()+1, &inotify_readfds, NULL, NULL, &waitd);
|
||||
if (( rc < 0 ) || ( rc == 0 ) || ( rc > (int)socks.size()))
|
||||
{
|
||||
/* Check to see if the select call failed. */
|
||||
/* ... but filter Interrupt signal */
|
||||
if (( rc < 0 ) && ( errno != EINTR ))
|
||||
{
|
||||
wlog_throttled ( select_failure_count, 20,
|
||||
"socket select failed (%d:%m)\n", errno);
|
||||
}
|
||||
else if ( rc > (int)socks.size())
|
||||
{
|
||||
wlog_throttled ( select_failure_count, 100,
|
||||
"Select return exceeds current file descriptors (%ld:%d)\n",
|
||||
socks.size(), rc );
|
||||
}
|
||||
else
|
||||
{
|
||||
select_failure_count = 0 ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wlog ( "inotify channel event\n");
|
||||
|
||||
for ( struct inst * inst_ptr = inst_head ; inst_ptr != NULL ; inst_ptr = inst_ptr->next )
|
||||
{
|
||||
if ( inst_ptr->instance.inotify_file_fd )
|
||||
{
|
||||
if (FD_ISSET(inst_ptr->instance.inotify_file_fd, &inotify_readfds) )
|
||||
{
|
||||
ilog ("Watch Event on instance %s\n", inst_ptr->instance.uuid.c_str());
|
||||
guestUtil_inotify_events (inst_ptr->instance.inotify_file_fd);
|
||||
}
|
||||
}
|
||||
if (( inst_ptr->next == NULL ) || ( inst_ptr == inst_tail ))
|
||||
break ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define MAX_LEN 300
|
||||
void daemon_service_run ( void )
|
||||
{
|
||||
int rc = 0 ;
|
||||
int count = 0 ;
|
||||
int flush_thld = 0 ;
|
||||
|
||||
string payload = "" ; /* for the ready event */
|
||||
|
||||
std::list<int> socks ;
|
||||
|
||||
guestUtil_load_channels ();
|
||||
|
||||
/* Setup inotify to watch for new instance serial IO channel creations */
|
||||
if ( set_inotify_watch ( QEMU_CHANNEL_DIR,
|
||||
ctrl.inotify_dir_fd,
|
||||
ctrl.inotify_dir_wd ) )
|
||||
{
|
||||
elog ("failed to setup inotify on %s\n", QEMU_CHANNEL_DIR );
|
||||
}
|
||||
|
||||
socks.clear();
|
||||
socks.push_front (ctrl.sock.server_rx_sock->getFD());
|
||||
if ( ctrl.inotify_dir_fd )
|
||||
socks.push_front (ctrl.inotify_dir_fd);
|
||||
else
|
||||
{
|
||||
elog ("unable to inotify monitor %s\n", QEMU_CHANNEL_DIR );
|
||||
|
||||
// TODO: consider exiting daemon
|
||||
}
|
||||
socks.sort();
|
||||
|
||||
mtcTimer_init ( ctrl.timer, ctrl.hostname );
|
||||
mtcTimer_init ( instInv.search_timer, ctrl.hostname );
|
||||
|
||||
mtcTimer_start ( ctrl.timer , guestTimer_handler, 2 );
|
||||
mtcTimer_start ( instInv.search_timer, guestTimer_handler, SEARCH_AUDIT_TIME );
|
||||
|
||||
ilog ("Selects: guestAgent:%d qemuDir:%d\n", ctrl.sock.server_rx_sock->getFD(), ctrl.inotify_dir_fd );
|
||||
ilog ("-------------------------------------------------------\n");
|
||||
|
||||
/* Tell the guestAgent that we started or restarted
|
||||
* so that it can send instance state data */
|
||||
payload = "{\"hostname\":\"" ;
|
||||
payload.append(ctrl.hostname);
|
||||
payload.append("\"}");
|
||||
|
||||
/* Run heartbeat service forever or until stop condition */
|
||||
for ( ; ; )
|
||||
{
|
||||
instInv.waitd.tv_sec = 0;
|
||||
instInv.waitd.tv_usec = GUEST_SOCKET_TO;
|
||||
|
||||
/* Initialize the master fd_set */
|
||||
FD_ZERO(&instInv.message_readfds);
|
||||
|
||||
FD_SET ( ctrl.sock.server_rx_sock->getFD(), &instInv.message_readfds);
|
||||
if ( ctrl.inotify_dir_fd )
|
||||
{
|
||||
FD_SET ( ctrl.inotify_dir_fd, &instInv.message_readfds);
|
||||
}
|
||||
|
||||
rc = select( socks.back()+1, &instInv.message_readfds, NULL, NULL, &instInv.waitd);
|
||||
if (( rc < 0 ) || ( rc == 0 ) || ( rc > (int)socks.size()))
|
||||
{
|
||||
/* Check to see if the select call failed. */
|
||||
/* ... but filter Interrupt signal */
|
||||
if (( rc < 0 ) && ( errno != EINTR ))
|
||||
{
|
||||
wlog_throttled ( count, 20, "socket select failed (%d:%m)\n", errno);
|
||||
}
|
||||
else if ( rc > (int)socks.size())
|
||||
{
|
||||
wlog_throttled ( count, 100, "Select return exceeds current file descriptors (%ld:%d)\n",
|
||||
socks.size(), rc );
|
||||
}
|
||||
else
|
||||
{
|
||||
count = 0 ;
|
||||
}
|
||||
}
|
||||
else if (FD_ISSET(ctrl.sock.server_rx_sock->getFD(), &instInv.message_readfds))
|
||||
{
|
||||
/* clean the rx/tx buffer */
|
||||
mtc_message_type msg ;
|
||||
memset ((void*)&msg,0,sizeof(mtc_message_type));
|
||||
|
||||
int bytes = ctrl.sock.server_rx_sock->read((char*)&msg.hdr[0], sizeof(mtc_message_type));
|
||||
ctrl.address_peer = ctrl.sock.server_rx_sock->get_src_str() ;
|
||||
mlog1 ("Received %d bytes from %s:%d:guestAgent\n", bytes,
|
||||
ctrl.sock.server_rx_sock->get_src_str(),
|
||||
ctrl.sock.server_rx_sock->get_dst_addr()->getPort() );
|
||||
print_mtc_message (&msg);
|
||||
|
||||
if ( bytes > 0 )
|
||||
{
|
||||
recv_from_guestAgent ( msg.cmd, &msg.buf[0] );
|
||||
}
|
||||
}
|
||||
|
||||
else if (FD_ISSET(ctrl.inotify_dir_fd, &instInv.message_readfds))
|
||||
{
|
||||
dlog ("%s dir change\n", QEMU_CHANNEL_DIR );
|
||||
|
||||
guestUtil_inotify_events (ctrl.inotify_dir_fd);
|
||||
}
|
||||
|
||||
fflush (stdout);
|
||||
fflush (stderr);
|
||||
|
||||
instInv.guest_fsm_run ( );
|
||||
|
||||
if ( ctrl.timer.ring == true )
|
||||
{
|
||||
/* restart the timer and try again if this call returns a RETRY */
|
||||
if ( send_to_guestAgent ( MTC_EVENT_MONITOR_READY, payload.data()) == RETRY )
|
||||
{
|
||||
mtcTimer_start ( ctrl.timer, guestTimer_handler, 5 );
|
||||
}
|
||||
ctrl.timer.ring = false ;
|
||||
}
|
||||
|
||||
daemon_signal_hdlr ();
|
||||
|
||||
/* Support the log flush config option */
|
||||
if ( guest_config.flush )
|
||||
{
|
||||
if ( ++flush_thld > guest_config.flush_thld )
|
||||
{
|
||||
flush_thld = 0 ;
|
||||
fflush (stdout);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
daemon_exit ();
|
||||
}
|
||||
/* Write the daemon /var/log/<daemon>.dump */
|
||||
void daemon_dump_info ( void )
|
||||
{
|
||||
daemon_dump_membuf_banner ();
|
||||
|
||||
instInv.print_node_info ();
|
||||
instInv.memDumpAllState ();
|
||||
|
||||
daemon_dump_membuf();
|
||||
}
|
||||
|
||||
const char MY_DATA [100] = { "eieio\n" } ;
|
||||
const char * daemon_stream_info ( void )
|
||||
{
|
||||
return (&MY_DATA[0]);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* Module Test Head *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
/** Teat Head Entry */
|
||||
int daemon_run_testhead ( void )
|
||||
{
|
||||
int rc = PASS;
|
||||
return (rc);
|
||||
}
|
18
mtce-guest/src/guestStubs.cpp
Normal file
18
mtce-guest/src/guestStubs.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2015 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Wind River CGTS Platform Nodal Health Check Agent Stubs
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "nodeBase.h"
|
||||
#include "nodeUtil.h"
|
93
mtce-guest/src/guestSvrFsm.cpp
Normal file
93
mtce-guest/src/guestSvrFsm.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2015 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* @file
|
||||
* Wind River CGTS Platform "Guest Services - Finite State Machine"
|
||||
*
|
||||
*
|
||||
* This FSM handles the following actions
|
||||
*
|
||||
* FSM_ACTION__CONNECT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "nodeBase.h"
|
||||
#include "nodeTimers.h"
|
||||
#include "guestBase.h"
|
||||
#include "guestInstClass.h"
|
||||
#include "guestSvrUtil.h"
|
||||
|
||||
void guestInstClass::fsm_run ( void )
|
||||
{
|
||||
int rc = PASS ;
|
||||
struct inst * inst_ptr = static_cast<struct inst *>(NULL) ;
|
||||
|
||||
if (( instances > 0 ) )
|
||||
{
|
||||
/* get new messages */
|
||||
readInst();
|
||||
|
||||
for ( inst_ptr = inst_head ; inst_ptr != NULL ; inst_ptr = inst_ptr->next )
|
||||
{
|
||||
if ( inst_ptr->message_list.size() )
|
||||
{
|
||||
guestInstClass::message_handler ( inst_ptr );
|
||||
}
|
||||
|
||||
if ( inst_ptr->action == FSM_ACTION__NONE )
|
||||
{
|
||||
guestInstClass::monitor_handler ( inst_ptr );
|
||||
}
|
||||
|
||||
else if ( inst_ptr->action == FSM_ACTION__CONNECT )
|
||||
{
|
||||
rc = guestInstClass::connect_handler ( inst_ptr );
|
||||
if ( rc == RETRY )
|
||||
return ;
|
||||
}
|
||||
else
|
||||
{
|
||||
slog ("unknown action (%d) for instance %s\n",
|
||||
inst_ptr->action, inst_ptr->instance.uuid.c_str());
|
||||
}
|
||||
|
||||
#ifdef WANT_LOSS_FIT
|
||||
if ( inst_ptr->heartbeat_count > 10 )
|
||||
{
|
||||
mtcTimer_stop ( inst_ptr->monitor_timer );
|
||||
mtcWait_secs (1);
|
||||
start_monitor_timer ( inst_ptr );
|
||||
inst_ptr->heartbeat_count = 0 ;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* exit if this happens to be the last one in the list */
|
||||
if (( inst_ptr->next == NULL ) || ( inst_ptr == inst_tail ))
|
||||
break ;
|
||||
}
|
||||
}
|
||||
else if ( inst_head != NULL )
|
||||
{
|
||||
slog ("head pointer is not NULL while there are no instances (%p)\n", inst_head );
|
||||
}
|
||||
|
||||
if ( search_timer.ring == true )
|
||||
{
|
||||
guestUtil_channel_search ();
|
||||
mtcTimer_start ( search_timer, guestTimer_handler, SEARCH_AUDIT_TIME );
|
||||
}
|
||||
|
||||
/* Make this part of the connect FSM */
|
||||
manage_comm_loss ( );
|
||||
}
|
1420
mtce-guest/src/guestSvrHdlr.cpp
Normal file
1420
mtce-guest/src/guestSvrHdlr.cpp
Normal file
File diff suppressed because it is too large
Load Diff
784
mtce-guest/src/guestSvrMsg.cpp
Normal file
784
mtce-guest/src/guestSvrMsg.cpp
Normal file
@ -0,0 +1,784 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2018 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Wind River CGTS Platform Guest Heartbeat Server Daemon on Compute
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <netdb.h> /* for hostent */
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h> /* for close and usleep */
|
||||
#include <sched.h> /* for realtime scheduling api */
|
||||
#include <json-c/json.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "nodeBase.h"
|
||||
#include "daemon_ini.h" /* Ini Parser Header */
|
||||
#include "daemon_common.h" /* Common definitions and types for daemons */
|
||||
#include "daemon_option.h" /* Common options for daemons */
|
||||
#include "nodeUtil.h" /* for ... common utilities */
|
||||
#include "jsonUtil.h" /* for ... jason utilities */
|
||||
#include "nodeTimers.h" /* for ... maintenance timers */
|
||||
#include "nodeMacro.h" /* for ... CREATE_NONBLOCK_INET_UDP_RX_SOCKET */
|
||||
#include "nodeEvent.h" /* for ... set_inotify_watch, set_inotify_close */
|
||||
#include "guestBase.h"
|
||||
#include "guestInstClass.h" /* for ... guestUtil_inst_init */
|
||||
#include "guestUtil.h" /* for ... guestUtil_inst_init */
|
||||
#include "guestSvrUtil.h" /* for ... hb_get_message_type_name */
|
||||
#include "guestSvrMsg.h" /* for ... this module header */
|
||||
|
||||
extern void hbStatusChange ( instInfo * instInfo_ptr, bool status );
|
||||
extern void beatStateChange ( instInfo * instInfo_ptr , hb_state_t newState );
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : guestSvrMsg_hdr_init
|
||||
*
|
||||
* Purpose: Initialize the message header. Example output:
|
||||
* {"version":2,"revision":1,"msg_type":"init","sequence":29,
|
||||
* The rest of the message should be appended to it.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
string guestSvrMsg_hdr_init (string channel, string msg_type)
|
||||
{
|
||||
instInfo * instInfo_ptr = get_instInv_ptr()->get_inst (channel);
|
||||
|
||||
string msg = "\n{\"";
|
||||
msg.append(GUEST_HEARTBEAT_MSG_VERSION);
|
||||
msg.append("\":");
|
||||
msg.append(int_to_string(GUEST_HEARTBEAT_MSG_VERSION_CURRENT));
|
||||
msg.append(",\"");
|
||||
msg.append(GUEST_HEARTBEAT_MSG_REVISION);
|
||||
msg.append("\":");
|
||||
msg.append(int_to_string(GUEST_HEARTBEAT_MSG_REVISION_CURRENT));
|
||||
msg.append(",\"");
|
||||
msg.append(GUEST_HEARTBEAT_MSG_MSG_TYPE);
|
||||
msg.append("\":\"");
|
||||
msg.append(msg_type);
|
||||
msg.append("\",\"");
|
||||
msg.append(GUEST_HEARTBEAT_MSG_SEQUENCE);
|
||||
msg.append("\":");
|
||||
msg.append(int_to_string(++(instInfo_ptr->sequence)));
|
||||
msg.append(",");
|
||||
|
||||
// store msg_type in instance structure so that it is available to handle timeout
|
||||
instInfo_ptr->msg_type = msg_type;
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages the fault reporting state
|
||||
* - returns current reporting state
|
||||
* */
|
||||
bool manage_reporting_state ( instInfo * instInfo_ptr, string state)
|
||||
{
|
||||
if (!state.compare("enabled"))
|
||||
{
|
||||
if ( instInfo_ptr->heartbeat.reporting == false )
|
||||
{
|
||||
ilog ("%s heartbeat reporting '%s' by guestAgent\n",
|
||||
log_prefix(instInfo_ptr).c_str(),
|
||||
state.c_str());
|
||||
|
||||
instInfo_ptr->heartbeat.reporting = true ;
|
||||
instInfo_ptr->message_count = 0 ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( instInfo_ptr->heartbeat.reporting == true )
|
||||
{
|
||||
ilog ("%s heartbeat reporting '%s' by guestAgent\n",
|
||||
log_prefix(instInfo_ptr).c_str(),
|
||||
state.c_str());
|
||||
|
||||
instInfo_ptr->heartbeat.reporting = false ;
|
||||
instInfo_ptr->message_count = 0 ;
|
||||
hbStatusChange ( instInfo_ptr, false) ; /* heartbeating is now false */
|
||||
beatStateChange ( instInfo_ptr, hbs_server_waiting_init ) ;
|
||||
}
|
||||
}
|
||||
|
||||
return instInfo_ptr->heartbeat.reporting ;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : guestAgent_qry_handler
|
||||
*
|
||||
* Purpose: Loop over all the instances and return their uuid, hostname,
|
||||
* reporting state, heartbneating status and timeout values.
|
||||
*
|
||||
* { "hostname":"compute-1", "instances": [{"uuid":"<uuid>","heartbeat":"<state>", status":"<status>}, timeouts ...]}
|
||||
*
|
||||
*****************************************************************************/
|
||||
int guestInstClass::guestAgent_qry_handler ( void )
|
||||
{
|
||||
int rc = PASS ;
|
||||
|
||||
/* check for empty list condition */
|
||||
if ( inst_head )
|
||||
{
|
||||
struct inst * inst_ptr = static_cast<struct inst *>(NULL) ;
|
||||
for ( inst_ptr = inst_head ; ; inst_ptr = inst_ptr->next )
|
||||
{
|
||||
string payload = guestUtil_set_inst_info ( get_ctrl_ptr()->hostname , &inst_ptr->instance );
|
||||
jlog ("%s Query Instance Response:%ld:%s\n",
|
||||
log_prefix(&inst_ptr->instance).c_str(),
|
||||
payload.size(),
|
||||
payload.c_str() );
|
||||
|
||||
if (( rc=send_to_guestAgent ( MTC_CMD_QRY_INST, payload.data())) != PASS )
|
||||
{
|
||||
wlog ("%s failed to send query instance response to guestAgent\n",
|
||||
log_prefix(&inst_ptr->instance).c_str());
|
||||
}
|
||||
|
||||
/* Deal with exit case */
|
||||
if (( inst_ptr->next == NULL ) || ( inst_ptr == inst_tail ))
|
||||
{
|
||||
break ;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : recv_from_guestAgent
|
||||
*
|
||||
* Purpose: Handle guestAgent commands
|
||||
*
|
||||
* MTC_EVENT_LOOPBACK
|
||||
* MTC_CMD_QRY_INST
|
||||
* MTC_CMD_DEL_INST
|
||||
* MTC_CMD_MOD_INST
|
||||
* MTC_CMD_ADD_INST
|
||||
* MTC_CMD_MOD_HOST
|
||||
*
|
||||
* ***************************************************************************/
|
||||
int recv_from_guestAgent ( unsigned int cmd, char * buf_ptr )
|
||||
{
|
||||
int rc = PASS ;
|
||||
|
||||
mlog1 ("Cmd:%x - %s\n", cmd, buf_ptr);
|
||||
|
||||
if ( cmd == MTC_EVENT_LOOPBACK )
|
||||
{
|
||||
/* TODO: Send message back */
|
||||
return (rc) ;
|
||||
}
|
||||
else if ( cmd == MTC_CMD_QRY_INST )
|
||||
{
|
||||
if ( ( rc = get_instInv_ptr()->qry_inst ()) != PASS )
|
||||
{
|
||||
elog ("failed to send hosts instance info\n");
|
||||
}
|
||||
return (rc) ;
|
||||
}
|
||||
else if ( cmd == MTC_CMD_VOTE_INST
|
||||
|| cmd == MTC_CMD_NOTIFY_INST )
|
||||
{
|
||||
string source;
|
||||
string uuid;
|
||||
string event;
|
||||
|
||||
rc = FAIL_KEY_VALUE_PARSE ; /* default to parse error */
|
||||
|
||||
if (( rc = jsonUtil_get_key_val ( buf_ptr, "source", source )) != PASS)
|
||||
{
|
||||
elog ("failed to extract 'source' (cmd:%x %s)\n", cmd , buf_ptr );
|
||||
}
|
||||
else if (( rc = jsonUtil_get_key_val ( buf_ptr, "uuid", uuid )) != PASS)
|
||||
{
|
||||
elog ("failed to extract 'uuid' (cmd:%x %s)\n", cmd , buf_ptr);
|
||||
}
|
||||
else if (( rc = jsonUtil_get_key_val ( buf_ptr, "event", event )) != PASS)
|
||||
{
|
||||
elog ("failed to extract 'event' key (cmd:%x %s)\n", cmd , buf_ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// send message to guest Client
|
||||
instInfo * instInfo_ptr = get_instInv_ptr()->get_inst(uuid);
|
||||
if ( instInfo_ptr )
|
||||
{
|
||||
/* If this is a resume then we need to reconnect to the channel */
|
||||
if ( !event.compare(GUEST_HEARTBEAT_MSG_EVENT_RESUME) )
|
||||
{
|
||||
/* issue a reconnect if we are not connected the hartbeating has not started */
|
||||
if (( instInfo_ptr->connected == false ) ||
|
||||
( instInfo_ptr->heartbeating == false ))
|
||||
{
|
||||
// instInfo_ptr->connect_wait_in_secs = 10 ;
|
||||
get_instInv_ptr()->reconnect_start ( instInfo_ptr->uuid.data() );
|
||||
}
|
||||
}
|
||||
|
||||
instInfo_ptr->event_type = event;
|
||||
if (MTC_CMD_VOTE_INST == cmd)
|
||||
{
|
||||
// for voting
|
||||
instInfo_ptr->notification_type = GUEST_HEARTBEAT_MSG_NOTIFY_REVOCABLE ;
|
||||
|
||||
ilog ("%s sending revocable '%s' vote\n",
|
||||
log_prefix(instInfo_ptr).c_str(),
|
||||
event.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// for notification
|
||||
instInfo_ptr->notification_type = GUEST_HEARTBEAT_MSG_NOTIFY_IRREVOCABLE ;
|
||||
|
||||
ilog ("%s sending irrevocable '%s' notify\n",
|
||||
log_prefix(instInfo_ptr).c_str(),
|
||||
event.c_str());
|
||||
}
|
||||
get_instInv_ptr()->send_vote_notify(uuid) ;
|
||||
rc = PASS ;
|
||||
}
|
||||
else
|
||||
{
|
||||
wlog ("%s is unknown\n", uuid.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string source ;
|
||||
string uuid ;
|
||||
string service ;
|
||||
string state ;
|
||||
|
||||
rc = FAIL_KEY_VALUE_PARSE ; /* default to parse error */
|
||||
|
||||
if (( rc = jsonUtil_get_key_val ( buf_ptr, "source", source )) != PASS)
|
||||
{
|
||||
elog ("failed to extract 'source' (cmd:%x %s)\n", cmd , buf_ptr );
|
||||
}
|
||||
else if (( rc = jsonUtil_get_key_val ( buf_ptr, "uuid", uuid )) != PASS)
|
||||
{
|
||||
elog ("failed to extract 'uuid' (cmd:%x %s)\n", cmd , buf_ptr);
|
||||
}
|
||||
else if (( rc = jsonUtil_get_key_val ( buf_ptr, "service", service )) != PASS)
|
||||
{
|
||||
elog ("failed to extract 'service' key (cmd:%x %s)\n", cmd , buf_ptr);
|
||||
}
|
||||
else if (( rc = jsonUtil_get_key_val ( buf_ptr, "state", state )) != PASS)
|
||||
{
|
||||
elog ("failed to extract 'state' (cmd:%x %s)\n", cmd , buf_ptr );
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = RETRY ;
|
||||
switch ( cmd )
|
||||
{
|
||||
case MTC_CMD_DEL_INST:
|
||||
{
|
||||
ilog ("%s delete\n", uuid.c_str());
|
||||
|
||||
if ( get_instInv_ptr()->del_inst( uuid ) == PASS )
|
||||
{
|
||||
rc = PASS ;
|
||||
}
|
||||
else
|
||||
{
|
||||
dlog ("%s delete failed ; uuid lookup\n", uuid.c_str());
|
||||
rc = FAIL_NOT_FOUND ;
|
||||
}
|
||||
if (daemon_get_cfg_ptr()->debug_level )
|
||||
get_instInv_ptr()->print_instances ();
|
||||
break ;
|
||||
}
|
||||
case MTC_CMD_ADD_INST:
|
||||
case MTC_CMD_MOD_INST:
|
||||
{
|
||||
instInfo * instInfo_ptr = get_instInv_ptr()->get_inst ( uuid );
|
||||
if ( instInfo_ptr )
|
||||
{
|
||||
manage_reporting_state ( instInfo_ptr, state );
|
||||
rc = PASS ;
|
||||
}
|
||||
|
||||
/* if true then the current channel was not found and we need to add it */
|
||||
if ( rc == RETRY )
|
||||
{
|
||||
instInfo instance ;
|
||||
guestUtil_inst_init (&instance);
|
||||
|
||||
instance.uuid = uuid ;
|
||||
ilog ("%s add with %s reporting %s\n",
|
||||
uuid.c_str(),
|
||||
service.c_str(),
|
||||
state.c_str());
|
||||
|
||||
get_instInv_ptr()->add_inst ( uuid, instance );
|
||||
instInfo * instInfo_ptr = get_instInv_ptr()->get_inst ( uuid );
|
||||
manage_reporting_state ( instInfo_ptr, state );
|
||||
}
|
||||
if (daemon_get_cfg_ptr()->debug_level )
|
||||
get_instInv_ptr()->print_instances();
|
||||
|
||||
break ;
|
||||
}
|
||||
case MTC_CMD_MOD_HOST:
|
||||
{
|
||||
guestInstClass * obj_ptr = get_instInv_ptr() ;
|
||||
string reporting_state = "" ;
|
||||
rc = jsonUtil_get_key_val ( buf_ptr, "heartbeat", reporting_state ) ;
|
||||
if ( rc != PASS)
|
||||
{
|
||||
elog ("failed to extract heartbeat reporting state (rc=%d)\n", rc );
|
||||
wlog ("... disabling 'heartbeat' fault reporting due to error\n");
|
||||
obj_ptr->reporting = false ;
|
||||
rc = FAIL_JSON_PARSE ;
|
||||
}
|
||||
else if ( !reporting_state.compare("enabled") )
|
||||
{
|
||||
ilog ("Enabling host level 'heartbeat' fault reporting\n");
|
||||
obj_ptr->reporting = true ;
|
||||
}
|
||||
else
|
||||
{
|
||||
ilog ("Disabling host level 'heartbeat' fault reporting\n");
|
||||
obj_ptr->reporting = false ;
|
||||
}
|
||||
break ;
|
||||
}
|
||||
default:
|
||||
{
|
||||
elog ("unsupported command (%x)\n", cmd );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Name : send_to_guestAgent
|
||||
*
|
||||
* Purpose : Send a command and buffer to the guestAgent
|
||||
*
|
||||
* Description: If the guestAgent IP is not known the message is dropped
|
||||
* and a retry is returned. Otherwise the supplied message is
|
||||
* sent to the guestAgent running on the controller.
|
||||
*
|
||||
* **************************************************************************/
|
||||
int send_to_guestAgent ( unsigned int cmd, const char * buf_ptr )
|
||||
{
|
||||
int bytes = 0;
|
||||
|
||||
ctrl_type * ctrl_ptr = get_ctrl_ptr () ;
|
||||
|
||||
int rc = PASS ;
|
||||
mtc_message_type mtc_cmd ;
|
||||
memset (&mtc_cmd,0,sizeof(mtc_message_type));
|
||||
|
||||
memcpy ( &mtc_cmd.buf[0], buf_ptr, strlen(buf_ptr));
|
||||
bytes = sizeof(mtc_message_type) ;
|
||||
|
||||
if ( ctrl_ptr->address_peer.empty())
|
||||
{
|
||||
mlog2 ("controller address unknown ; dropping message (%x:%s)", cmd , buf_ptr );
|
||||
return RETRY ;
|
||||
}
|
||||
|
||||
mlog1 ("Sending: %s:%d Cmd:%x:%s\n", ctrl_ptr->address_peer.c_str(), ctrl_ptr->sock.agent_rx_port, cmd, buf_ptr );
|
||||
|
||||
mtc_cmd.cmd = cmd ;
|
||||
|
||||
/* rc = message size */
|
||||
rc = ctrl_ptr->sock.server_tx_sock->write((char *)&mtc_cmd, bytes,ctrl_ptr->address_peer.c_str());
|
||||
|
||||
if ( 0 > rc )
|
||||
{
|
||||
elog("failed to send (%d:%m)\n", errno );
|
||||
rc = FAIL_SOCKET_SENDTO ;
|
||||
}
|
||||
else
|
||||
{
|
||||
mlog1 ("Transmit to %14s port %d\n",
|
||||
ctrl_ptr->address_peer.c_str(),
|
||||
ctrl_ptr->sock.server_tx_sock->get_dst_addr()->getPort());
|
||||
print_mtc_message ( &mtc_cmd );
|
||||
rc = PASS ;
|
||||
}
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/*********************************************************************************
|
||||
*
|
||||
* Name : write_inst (guestInstClass::public)
|
||||
*
|
||||
* Purpose: Send a message to the specified VM instance.
|
||||
*
|
||||
*********************************************************************************/
|
||||
ssize_t guestInstClass::write_inst ( instInfo * instInfo_ptr,
|
||||
const char * message,
|
||||
size_t size)
|
||||
{
|
||||
string name = log_prefix(instInfo_ptr);
|
||||
|
||||
errno = 0 ;
|
||||
size_t len = write ( instInfo_ptr->chan_fd, message, size );
|
||||
if ( len != size )
|
||||
{
|
||||
if ( errno )
|
||||
{
|
||||
wlog_throttled ( instInfo_ptr->failure_count, 100,
|
||||
"%s failed to send '%s' (seq:%x) (%d:%m)\n", name.c_str(),
|
||||
instInfo_ptr->msg_type.c_str(),
|
||||
instInfo_ptr->sequence, errno );
|
||||
|
||||
if ( errno == EPIPE )
|
||||
{
|
||||
instInfo_ptr->connected = false ;
|
||||
|
||||
instInfo_ptr->connect_wait_in_secs = DEFAULT_CONNECT_WAIT ;
|
||||
get_instInv_ptr()->reconnect_start ( instInfo_ptr->uuid.data() );
|
||||
}
|
||||
|
||||
len = 0 ;
|
||||
}
|
||||
else
|
||||
{
|
||||
wlog_throttled ( instInfo_ptr->failure_count, 100,
|
||||
"%s send '%s' (seq:%x) (len:%ld)\n", name.c_str(),
|
||||
instInfo_ptr->msg_type.c_str(),
|
||||
instInfo_ptr->sequence, len);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
instInfo_ptr->failure_count = 0 ;
|
||||
mlog("%s send '%s' (seq:%x)\n", name.c_str(),
|
||||
instInfo_ptr->msg_type.c_str(),
|
||||
instInfo_ptr->sequence );
|
||||
}
|
||||
return (len);
|
||||
}
|
||||
|
||||
/*********************************************************************************
|
||||
*
|
||||
* Name : process_msg (guestInstClass::private)
|
||||
*
|
||||
* Purpose : process delimited message
|
||||
*
|
||||
*********************************************************************************/
|
||||
void guestInstClass::process_msg(json_object *jobj_msg,
|
||||
struct guestInstClass::inst * inst_ptr)
|
||||
{
|
||||
int version;
|
||||
string msg_type;
|
||||
string log_err = "failed to parse ";
|
||||
guestInstClass * obj_ptr = get_instInv_ptr();
|
||||
|
||||
//parse incoming msg
|
||||
if (jobj_msg == NULL)
|
||||
{
|
||||
wlog("%s\n", log_err.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (jsonUtil_get_int(jobj_msg, GUEST_HEARTBEAT_MSG_VERSION, &version) != PASS)
|
||||
{
|
||||
// fail to parse the version
|
||||
log_err.append(GUEST_HEARTBEAT_MSG_VERSION);
|
||||
elog("%s\n", log_err.c_str());
|
||||
obj_ptr->send_client_msg_nack(&inst_ptr->instance, log_err);
|
||||
json_object_put(jobj_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( version < GUEST_HEARTBEAT_MSG_VERSION_CURRENT)
|
||||
{
|
||||
char log_err_str[100];
|
||||
sprintf(log_err_str, "Bad version: %d, expect version: %d",
|
||||
version, GUEST_HEARTBEAT_MSG_VERSION_CURRENT);
|
||||
elog("%s\n", log_err_str);
|
||||
log_err = log_err_str;
|
||||
obj_ptr->send_client_msg_nack(&inst_ptr->instance, log_err);
|
||||
json_object_put(jobj_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (jsonUtil_get_string(jobj_msg, GUEST_HEARTBEAT_MSG_MSG_TYPE, &msg_type) != PASS)
|
||||
{
|
||||
// fail to parse the msg_type
|
||||
log_err.append(GUEST_HEARTBEAT_MSG_MSG_TYPE);
|
||||
elog("%s\n", log_err.c_str());
|
||||
obj_ptr->send_client_msg_nack(&inst_ptr->instance, log_err);
|
||||
json_object_put(jobj_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Enqueue the message to its instance message list */
|
||||
inst_ptr->message_list.push_back(jobj_msg);
|
||||
}
|
||||
|
||||
/*********************************************************************************
|
||||
*
|
||||
* Name : parser (guestInstClass::private)
|
||||
*
|
||||
* Purpose : parse message segments and feed valid message to process_msg
|
||||
*
|
||||
*********************************************************************************/
|
||||
void guestInstClass::parser(char *buf,
|
||||
ssize_t len,
|
||||
json_tokener* tok,
|
||||
int newline_found,
|
||||
struct guestInstClass::inst * inst_ptr)
|
||||
{
|
||||
json_object *jobj = json_tokener_parse_ex(tok, buf, len);
|
||||
enum json_tokener_error jerr = json_tokener_get_error(tok);
|
||||
|
||||
if (jerr == json_tokener_success) {
|
||||
process_msg(jobj, inst_ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
else if (jerr == json_tokener_continue) {
|
||||
// partial JSON is parsed , continue to read from socket.
|
||||
if (newline_found) {
|
||||
// if newline was found in the middle of the buffer, the message
|
||||
// should be completed at this point. Throw out incomplete message
|
||||
// by resetting tokener.
|
||||
json_tokener_reset(tok);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// parsing error
|
||||
json_tokener_reset(tok);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************
|
||||
*
|
||||
* Name : handle_virtio_serial_msg (guestInstClass::private)
|
||||
*
|
||||
* Purpose : handle delimitation and assembly of message stream
|
||||
*
|
||||
* Description: Multiple messages from the host can be bundled together into a
|
||||
* single "read" so we need to check message boundaries and handle
|
||||
* breaking the message apart. Assume a valid message does not
|
||||
* contain newline '\n', and newline is added to the beginning and
|
||||
* end of each message by the sender to delimit the boundaries.
|
||||
*
|
||||
*********************************************************************************/
|
||||
void guestInstClass::handle_virtio_serial_msg(
|
||||
char *buf,
|
||||
ssize_t len,
|
||||
json_tokener* tok,
|
||||
struct guestInstClass::inst * inst_ptr)
|
||||
{
|
||||
char *newline;
|
||||
ssize_t len_head;
|
||||
|
||||
next:
|
||||
if (len <= 0)
|
||||
return;
|
||||
|
||||
// search for newline as delimiter
|
||||
newline = (char *)memchr((char *)buf, '\n', len);
|
||||
|
||||
if (newline) {
|
||||
// split buffer to head and tail at the location of newline.
|
||||
// feed the head to the parser and recursively process the tail.
|
||||
len_head = newline-buf;
|
||||
|
||||
// parse head
|
||||
if (len_head > 0)
|
||||
parser(buf, len_head, tok, 1, inst_ptr);
|
||||
|
||||
// start of the tail: skip newline
|
||||
buf += len_head+1;
|
||||
// length of the tail: deduct 1 for the newline character
|
||||
len -= len_head+1;
|
||||
|
||||
// continue to process the tail.
|
||||
goto next;
|
||||
}
|
||||
else {
|
||||
parser(buf, len, tok, 0, inst_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************
|
||||
*
|
||||
* Name : readInst (guestInstClass::private)
|
||||
*
|
||||
* Purpose : try to receive a single message from all instances.
|
||||
*
|
||||
* Description: Each received message is enqueued into the associated
|
||||
* instance's message queue.
|
||||
*
|
||||
*********************************************************************************/
|
||||
|
||||
int fail_count = 0 ;
|
||||
void guestInstClass::readInst ( void )
|
||||
{
|
||||
int rc ;
|
||||
std::list<int> socks ;
|
||||
|
||||
waitd.tv_sec = 0;
|
||||
waitd.tv_usec = GUEST_SOCKET_TO;
|
||||
|
||||
/* Initialize the master fd_set */
|
||||
FD_ZERO(&instance_readfds);
|
||||
|
||||
socks.clear();
|
||||
|
||||
for ( struct inst * inst_ptr = inst_head ; inst_ptr != NULL ; inst_ptr = inst_ptr->next )
|
||||
{
|
||||
if ( inst_ptr->instance.connected )
|
||||
{
|
||||
socks.push_front( inst_ptr->instance.chan_fd );
|
||||
FD_SET(inst_ptr->instance.chan_fd, &instance_readfds);
|
||||
}
|
||||
if (( inst_ptr->next == NULL ) || ( inst_ptr == inst_tail ))
|
||||
break ;
|
||||
}
|
||||
|
||||
/* if there are no connected instance channels then exit */
|
||||
if ( socks.empty() )
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
/* Call select() and wait only up to SOCKET_WAIT */
|
||||
socks.sort();
|
||||
rc = select( socks.back()+1, &instance_readfds, NULL, NULL, &waitd);
|
||||
|
||||
if (( rc <= 0 ) || ( rc > (int)socks.size()))
|
||||
{
|
||||
/* Check to see if the select call failed. */
|
||||
if ( rc > (int)socks.size())
|
||||
{
|
||||
wlog_throttled ( fail_count, 100, "select return exceeds current file descriptors (%ld:%d)\n",
|
||||
socks.size(), rc );
|
||||
}
|
||||
/* ... but filter Interrupt signal */
|
||||
else if (( rc < 0 ) && ( errno != EINTR ))
|
||||
{
|
||||
wlog_throttled ( fail_count, 100, "socket select failed (%d:%m)\n", errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
mlog3 ("nothing received from %ld instances; socket timeout (%d:%m)\n", socks.size(), errno );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fail_count = 0 ;
|
||||
mlog2 ("trying to receive for %ld instances\n", socks.size());
|
||||
|
||||
/* Search through all the instances for watched channels */
|
||||
for ( struct inst * inst_ptr = inst_head ; inst_ptr != NULL ; inst_ptr = inst_ptr->next )
|
||||
{
|
||||
mlog2 ("%s monitoring %d\n", inst_ptr->instance.inst.c_str(),
|
||||
inst_ptr->instance.chan_fd );
|
||||
|
||||
/* Service guestServer messages towards the local IP */
|
||||
if (FD_ISSET(inst_ptr->instance.chan_fd, &instance_readfds) )
|
||||
{
|
||||
char buf[GUEST_HEARTBEAT_MSG_MAX_MSG_SIZE] ;
|
||||
string name ;
|
||||
|
||||
if( inst_ptr->instance.inst.empty() )
|
||||
name = inst_ptr->instance.uuid ;
|
||||
else
|
||||
name = inst_ptr->instance.inst ;
|
||||
|
||||
struct json_tokener* tok = json_tokener_new();
|
||||
|
||||
for ( int i = 0; i < INST_MSG_READ_COUNT; i++ )
|
||||
{
|
||||
rc = read ( inst_ptr->instance.chan_fd, buf, GUEST_HEARTBEAT_MSG_MAX_MSG_SIZE);
|
||||
mlog2 ("%s read channel: bytes:%d, fd:%d\n", name.c_str(), rc,inst_ptr->instance.chan_fd );
|
||||
if ( rc < 0 )
|
||||
{
|
||||
if ( errno == EINTR )
|
||||
{
|
||||
wlog_throttled ( inst_ptr->instance.failure_count, 100, "%s EINTR\n", name.c_str());
|
||||
}
|
||||
else if ( errno == ECONNRESET )
|
||||
{
|
||||
wlog ("%s connection reset ... closing\n", name.c_str());
|
||||
|
||||
/* Close the connection if we get a 'connection reset by peer' errno */
|
||||
guestUtil_close_channel ( &inst_ptr->instance );
|
||||
|
||||
/* An element of the list is removed - need to break out */
|
||||
}
|
||||
else if ( errno != EAGAIN )
|
||||
{
|
||||
wlog_throttled ( inst_ptr->instance.failure_count, 100, "%s error (%d:%m)\n", name.c_str(), errno );
|
||||
}
|
||||
else
|
||||
{
|
||||
mlog3 ("%s no more messages\n", name.c_str());
|
||||
}
|
||||
break ;
|
||||
}
|
||||
else if ( rc == 0 )
|
||||
{
|
||||
mlog3 ("%s no message\n" , name.c_str());
|
||||
break ;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( rc < GUEST_HEARTBEAT_MSG_MIN_MSG_SIZE )
|
||||
{
|
||||
wlog_throttled ( inst_ptr->instance.failure_count, 100,
|
||||
"%s message size %d is smaller than minimal %d; dropping\n",
|
||||
name.c_str(), rc, GUEST_HEARTBEAT_MSG_MIN_MSG_SIZE);
|
||||
}
|
||||
else if ( inst_ptr->message_list.size() > MAX_MESSAGES )
|
||||
{
|
||||
wlog_throttled ( inst_ptr->instance.failure_count, 100,
|
||||
"%s message queue overflow (max:%d) ; dropping\n",
|
||||
name.c_str(), MAX_MESSAGES );
|
||||
}
|
||||
else
|
||||
{
|
||||
inst_ptr->instance.failure_count = 0 ;
|
||||
mlog2 ("%s handling message buf: %s\n", name.c_str(), buf );
|
||||
handle_virtio_serial_msg(buf, rc, tok, inst_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
json_tokener_free(tok);
|
||||
}
|
||||
if (( inst_ptr->next == NULL ) || ( inst_ptr == inst_tail ))
|
||||
break ;
|
||||
}
|
||||
}
|
||||
}
|
27
mtce-guest/src/guestSvrMsg.h
Normal file
27
mtce-guest/src/guestSvrMsg.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef __INCLUDE_GUESTSVRMSG_H__
|
||||
#define __INCLUDE_GUESTSVRMSG_H__
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013-2016 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Wind River CGTS Platform Guest Services "Messaging" Header
|
||||
*/
|
||||
|
||||
#include "guestBase.h"
|
||||
#include "guestInstClass.h" /* for ... */
|
||||
|
||||
/* Send a command and buffer to the guestAgent */
|
||||
int send_to_guestAgent ( unsigned int cmd,
|
||||
const char * buf_ptr );
|
||||
|
||||
int recv_from_guestAgent ( unsigned int cmd, char * buf_ptr );
|
||||
|
||||
string guestSvrMsg_hdr_init (string channel, string msg_type);
|
||||
|
||||
#endif /* __INCLUDE_GUESTSVRMSG_H__ */
|
234
mtce-guest/src/guestSvrUtil.cpp
Normal file
234
mtce-guest/src/guestSvrUtil.cpp
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "nodeBase.h" /* for ... */
|
||||
#include "nodeEvent.h" /* for ... inotify_event_queue_type and utils */
|
||||
#include "nodeTimers.h" /* maintenance timer utilities start/stop */
|
||||
|
||||
#include "guestInstClass.h"
|
||||
#include "guestUtil.h" /* for ... guestUtil_inst_init */
|
||||
#include "guestSvrUtil.h" /* for ... this module header */
|
||||
#include "guestVirtio.h" /* for ... virtio_check_filename,
|
||||
virtio_channel_add */
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : guestUtil_close_channel
|
||||
*
|
||||
* Purpose: Close the specified channel's virtio channel file descriptor.
|
||||
*
|
||||
******************************************************************************/
|
||||
int guestUtil_close_channel ( instInfo * instInfo_ptr )
|
||||
{
|
||||
int rc = FAIL_NOT_FOUND ;
|
||||
if ( instInfo_ptr )
|
||||
{
|
||||
/* Free up the inotify watch */
|
||||
if ( instInfo_ptr->inotify_file_fd )
|
||||
{
|
||||
dlog ("%s freeing inotify resource\n", log_prefix(instInfo_ptr).c_str() );
|
||||
set_inotify_close (instInfo_ptr->inotify_file_fd ,
|
||||
instInfo_ptr->inotify_file_wd );
|
||||
}
|
||||
|
||||
if ( instInfo_ptr->chan_fd )
|
||||
{
|
||||
dlog ("%s closing socket %d\n",
|
||||
log_prefix(instInfo_ptr).c_str(),
|
||||
instInfo_ptr->chan_fd );
|
||||
|
||||
close ( instInfo_ptr->chan_fd );
|
||||
instInfo_ptr->chan_fd = 0 ;
|
||||
}
|
||||
instInfo_ptr->chan_ok = false ;
|
||||
instInfo_ptr->heartbeating = false ;
|
||||
instInfo_ptr->connected = false ;
|
||||
rc = PASS ;
|
||||
}
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : guestUtil_load_channels
|
||||
*
|
||||
* Purpose: Scan the Virtio Qemu directory looking for heartbeat channels
|
||||
* into guests.
|
||||
*
|
||||
* Load those that are found into the control structure
|
||||
* and setup messaging to them.
|
||||
*
|
||||
******************************************************************************/
|
||||
void guestUtil_load_channels ( void )
|
||||
{
|
||||
DIR *dirp;
|
||||
struct dirent entry;
|
||||
struct dirent *result;
|
||||
|
||||
dirp = opendir(QEMU_CHANNEL_DIR);
|
||||
if (!dirp)
|
||||
{
|
||||
elog("failed to open %s directory (%d:%m)\n", QEMU_CHANNEL_DIR, errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
dlog ("Searching %s directory\n", QEMU_CHANNEL_DIR);
|
||||
while(0 == readdir_r(dirp, &entry, &result))
|
||||
{
|
||||
if (!result)
|
||||
break;
|
||||
|
||||
if ( virtio_check_filename (result->d_name) )
|
||||
{
|
||||
string channel = result->d_name ;
|
||||
ilog ("%s found\n", channel.c_str() );
|
||||
if ( virtio_channel_add ( result->d_name ) == PASS )
|
||||
{
|
||||
if ( virtio_channel_connect ( channel ) != PASS )
|
||||
{
|
||||
string uuid = virtio_instance_name ( result->d_name ) ;
|
||||
get_instInv_ptr()->reconnect_start ( uuid.data() );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dlog3 ("ignoring file %s\n", result->d_name);
|
||||
}
|
||||
}
|
||||
closedir(dirp);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : guestUtil_channel_search
|
||||
*
|
||||
* Purpose: Scan the Virtio Qemu directory looking for heartbeat channels
|
||||
* into guests that are not currently provisioned.
|
||||
*
|
||||
******************************************************************************/
|
||||
void guestUtil_channel_search ( void )
|
||||
{
|
||||
DIR *dirp;
|
||||
struct dirent entry;
|
||||
struct dirent *result;
|
||||
|
||||
dirp = opendir(QEMU_CHANNEL_DIR);
|
||||
if (!dirp)
|
||||
{
|
||||
elog("failed to open %s directory (%d:%m)\n", QEMU_CHANNEL_DIR, errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
dlog ("Searching %s directory\n", QEMU_CHANNEL_DIR);
|
||||
while(0 == readdir_r(dirp, &entry, &result))
|
||||
{
|
||||
if (!result)
|
||||
break;
|
||||
|
||||
if ( virtio_check_filename (result->d_name) )
|
||||
{
|
||||
if ( get_instInv_ptr()->get_inst ( virtio_instance_name (result->d_name).data()) == NULL )
|
||||
{
|
||||
string channel = result->d_name ;
|
||||
ilog ("found %s\n", channel.c_str() );
|
||||
virtio_channel_add ( result->d_name );
|
||||
virtio_channel_connect ( channel );
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dirp);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : guestUtil_inotify_events
|
||||
*
|
||||
* Purpose: Handle inotify events for the specified file descriptor.
|
||||
*
|
||||
*****************************************************************************/
|
||||
int guestUtil_inotify_events ( int fd )
|
||||
{
|
||||
string channel = "" ;
|
||||
inotify_event_queue_type event_queue ;
|
||||
int num = get_inotify_events ( fd , event_queue ) ;
|
||||
|
||||
dlog3 ("inotify events queued: %d\n", num );
|
||||
|
||||
for ( int i = 0 ; i < num ; i++ )
|
||||
{
|
||||
dlog2 ( "Event:%s for file:%s\n", get_inotify_event_str(event_queue.item[i].event), event_queue.item[i].name );
|
||||
|
||||
if ( event_queue.item[i].event == IN_CREATE )
|
||||
{
|
||||
dlog1 ("%s CREATE event on %s\n", event_queue.item[i].name, QEMU_CHANNEL_DIR );
|
||||
if ( virtio_check_filename (&event_queue.item[i].name[0]) )
|
||||
{
|
||||
dlog ("%s CREATE accepted\n", event_queue.item[i].name );
|
||||
channel = event_queue.item[i].name ;
|
||||
if ( virtio_channel_add ( event_queue.item[i].name ) != PASS )
|
||||
{
|
||||
elog ("%s failed to add detected channel\n", event_queue.item[i].name );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( event_queue.item[i].event == IN_DELETE )
|
||||
{
|
||||
dlog1 ("%s DELETE event on %s\n", event_queue.item[i].name, QEMU_CHANNEL_DIR );
|
||||
if ( virtio_check_filename (&event_queue.item[i].name[0]) )
|
||||
{
|
||||
dlog ("%s DELETE accepted\n", event_queue.item[i].name );
|
||||
channel = event_queue.item[i].name ;
|
||||
get_instInv_ptr()->del_inst ( channel );
|
||||
}
|
||||
else
|
||||
{
|
||||
dlog ("%s DELETE rejected\n", event_queue.item[i].name );
|
||||
}
|
||||
}
|
||||
else if ( event_queue.item[i].event == IN_MODIFY )
|
||||
{
|
||||
dlog1 ("%s MODIFY event on %s\n", event_queue.item[i].name, QEMU_CHANNEL_DIR );
|
||||
if ( virtio_check_filename (&event_queue.item[i].name[0]) )
|
||||
{
|
||||
dlog ("%s MODIFY accepted\n", event_queue.item[i].name );
|
||||
channel = event_queue.item[i].name ;
|
||||
|
||||
/* if the channel was modified then we need
|
||||
*
|
||||
* 1. to close the channel,
|
||||
* 2. delete it,
|
||||
* 3. re-add it and
|
||||
* 4. then repoen it.
|
||||
* */
|
||||
get_instInv_ptr()->del_inst ( channel );
|
||||
|
||||
if ( virtio_channel_add ( event_queue.item[i].name ) != PASS )
|
||||
{
|
||||
elog ("%s failed to re-add modified channel\n", channel.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wlog ("%s UNKNOWN event on %s\n", event_queue.item[i].name, QEMU_CHANNEL_DIR );
|
||||
}
|
||||
}
|
||||
return (PASS);
|
||||
}
|
18
mtce-guest/src/guestSvrUtil.h
Normal file
18
mtce-guest/src/guestSvrUtil.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef __INCLUDE_GUESTSVRUTIL_H__
|
||||
#define __INCLUDE_GUESTSVRUTIL_H__
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
#include "guestBase.h" /* for ... instInfo */
|
||||
|
||||
int guestUtil_close_channel ( instInfo * instInfo_ptr );
|
||||
void guestUtil_load_channels ( void );
|
||||
int guestUtil_inotify_events ( int fd );
|
||||
void guestUtil_channel_search ( void ) ;
|
||||
|
||||
#endif /* __INCLUDE_GUESTSVRUTIL_H__ */
|
330
mtce-guest/src/guestUtil.cpp
Normal file
330
mtce-guest/src/guestUtil.cpp
Normal file
@ -0,0 +1,330 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2016 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sstream>
|
||||
using namespace std;
|
||||
|
||||
#include "guestBase.h"
|
||||
#include "guestUtil.h"
|
||||
#include "guestClass.h"
|
||||
#include "jsonUtil.h"
|
||||
|
||||
#define MAX_NUM_LEN 64
|
||||
string time_in_secs_to_str ( time_t secs )
|
||||
{
|
||||
char int_str[MAX_NUM_LEN] ;
|
||||
string temp ;
|
||||
memset ( &int_str[0], 0, MAX_NUM_LEN );
|
||||
sprintf ( &int_str[0], "%ld" , secs );
|
||||
temp = int_str ;
|
||||
return (temp);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : guestUtil_inst_init
|
||||
*
|
||||
* Purpose: Init the specified instance
|
||||
*
|
||||
*****************************************************************************/
|
||||
void guestUtil_inst_init ( instInfo * instance_ptr )
|
||||
{
|
||||
instance_ptr->uuid.clear(); /* Not used in the server */
|
||||
|
||||
instance_ptr->inotify_file_fd = 0 ;
|
||||
instance_ptr->inotify_file_wd = 0 ;
|
||||
|
||||
instance_ptr->chan_fd = 0 ;
|
||||
instance_ptr->chan_ok = false ;
|
||||
instance_ptr->connected = false ; /* Assume we have not connected to this channel */
|
||||
instance_ptr->heartbeating = false ;
|
||||
|
||||
instance_ptr->heartbeat.provisioned = false ;
|
||||
instance_ptr->heartbeat.reporting = false ;
|
||||
instance_ptr->heartbeat.failures = 0 ;
|
||||
|
||||
instance_ptr->heartbeat.state.clear() ;
|
||||
|
||||
instance_ptr->hbState = hbs_server_waiting_init ;
|
||||
instance_ptr->vnState = hbs_server_waiting_init ;
|
||||
|
||||
instance_ptr->connect_count = 0 ;
|
||||
instance_ptr->connect_retry_count = 0 ;
|
||||
instance_ptr->select_count = 0 ;
|
||||
instance_ptr->message_count = 0 ;
|
||||
instance_ptr->health_count = 0 ;
|
||||
instance_ptr->failure_count = 0 ;
|
||||
instance_ptr->corrective_action_count = 0 ;
|
||||
|
||||
instance_ptr->unhealthy_failure = false ;
|
||||
|
||||
instance_ptr->heartbeat_interval_ms = HB_DEFAULT_INTERVAL_MS;
|
||||
|
||||
instance_ptr->vote_secs = HB_DEFAULT_VOTE_MS/1000;
|
||||
instance_ptr->vote_to_str = time_in_secs_to_str (instance_ptr->vote_secs);
|
||||
|
||||
instance_ptr->shutdown_notice_secs = HB_DEFAULT_SHUTDOWN_MS/1000;
|
||||
instance_ptr->shutdown_to_str = time_in_secs_to_str (instance_ptr->shutdown_notice_secs);
|
||||
|
||||
instance_ptr->suspend_notice_secs = HB_DEFAULT_SUSPEND_MS/1000;
|
||||
instance_ptr->suspend_to_str = time_in_secs_to_str (instance_ptr->suspend_notice_secs);
|
||||
|
||||
instance_ptr->resume_notice_secs = HB_DEFAULT_RESUME_MS/1000;
|
||||
instance_ptr->resume_to_str = time_in_secs_to_str (instance_ptr->resume_notice_secs);
|
||||
|
||||
instance_ptr->restart_secs = HB_DEFAULT_RESTART_MS/1000;
|
||||
instance_ptr->restart_to_str = time_in_secs_to_str(instance_ptr->restart_secs);
|
||||
|
||||
instance_ptr->notification_type = GUEST_HEARTBEAT_MSG_NOTIFY_IRREVOCABLE ;
|
||||
instance_ptr->event_type = GUEST_HEARTBEAT_MSG_EVENT_RESUME ;
|
||||
|
||||
instance_ptr->corrective_action = GUEST_HEARTBEAT_MSG_ACTION_LOG ;
|
||||
|
||||
instance_ptr->unhealthy_corrective_action = GUEST_HEARTBEAT_MSG_ACTION_UNKNOWN ;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : guestUtil_print_instance
|
||||
*
|
||||
* Purpose: Print a summary of the instances that are currently provisioned
|
||||
*
|
||||
*****************************************************************************/
|
||||
void guestUtil_print_instance ( instInfo * instInfo_ptr )
|
||||
{
|
||||
ilog ("%s Heartbeat: Prov-%c Reporting-%c Failures:%d\n",
|
||||
instInfo_ptr->uuid.c_str(),
|
||||
instInfo_ptr->heartbeat.provisioned ? 'Y':'n' ,
|
||||
instInfo_ptr->heartbeat.reporting ? 'Y':'n',
|
||||
instInfo_ptr->heartbeat.failures);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : guestUtil_print_instances
|
||||
*
|
||||
* Purpose: Print a summary of the instances that are currently provisioned
|
||||
*
|
||||
*****************************************************************************/
|
||||
void guestUtil_print_instances ( ctrl_type * ctrl_ptr )
|
||||
{
|
||||
bool found = false ;
|
||||
int i = 1 ;
|
||||
|
||||
for ( ctrl_ptr->instance_list_ptr = ctrl_ptr->instance_list.begin();
|
||||
ctrl_ptr->instance_list_ptr != ctrl_ptr->instance_list.end();
|
||||
ctrl_ptr->instance_list_ptr++ )
|
||||
{
|
||||
guestUtil_print_instance ( &(*ctrl_ptr->instance_list_ptr) );
|
||||
found = true ;
|
||||
i++ ;
|
||||
}
|
||||
|
||||
if ( found == false )
|
||||
{
|
||||
ilog ("no heartbeat channels provisioned\n");
|
||||
}
|
||||
}
|
||||
|
||||
string log_prefix ( instInfo * instInfo_ptr )
|
||||
{
|
||||
string prefix = "unknown" ;
|
||||
|
||||
if ( instInfo_ptr )
|
||||
{
|
||||
if ( instInfo_ptr->name.length() )
|
||||
{
|
||||
if ( instInfo_ptr->name_log_prefix.empty() )
|
||||
{
|
||||
instInfo_ptr->name_log_prefix = instInfo_ptr->inst ;
|
||||
instInfo_ptr->name_log_prefix.append (" ");
|
||||
instInfo_ptr->name_log_prefix.append (instInfo_ptr->name);
|
||||
}
|
||||
prefix = instInfo_ptr->name_log_prefix ;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( instInfo_ptr->uuid_log_prefix.empty() )
|
||||
{
|
||||
instInfo_ptr->uuid_log_prefix = instInfo_ptr->uuid ;
|
||||
}
|
||||
prefix = instInfo_ptr->uuid_log_prefix ;
|
||||
}
|
||||
}
|
||||
return (prefix);
|
||||
}
|
||||
|
||||
string guestUtil_set_inst_info ( string hostname , instInfo * instInfo_ptr )
|
||||
{
|
||||
/* Send one message per instance */
|
||||
string payload ("{\"hostname\":\"");
|
||||
payload.append (hostname);
|
||||
payload.append ("\",\"uuid\":\"");
|
||||
payload.append (instInfo_ptr->uuid);
|
||||
|
||||
/* Share the reporting state */
|
||||
payload.append ("\",\"reporting\":");
|
||||
if ( instInfo_ptr->heartbeat.reporting == true )
|
||||
payload.append ("\"enabled");
|
||||
else
|
||||
payload.append ("\"disabled");
|
||||
|
||||
/* Share the heartbeating state */
|
||||
payload.append ("\",\"heartbeating\":");
|
||||
if ( instInfo_ptr->heartbeating == true )
|
||||
payload.append ("\"enabled");
|
||||
else
|
||||
payload.append ("\"disabled");
|
||||
|
||||
payload.append ("\",\"repair-action\":\"" );
|
||||
if ( instInfo_ptr->unhealthy_failure == true )
|
||||
{
|
||||
payload.append (instInfo_ptr->unhealthy_corrective_action);
|
||||
}
|
||||
else
|
||||
{
|
||||
payload.append (instInfo_ptr->corrective_action);
|
||||
}
|
||||
/* Add the restart timeout to the message */
|
||||
payload.append ("\",\"restart-to\":\"");
|
||||
payload.append (instInfo_ptr->restart_to_str);
|
||||
payload.append ("\",\"shutdown-to\":\"");
|
||||
payload.append (instInfo_ptr->shutdown_to_str);
|
||||
payload.append ("\",\"suspend-to\":\"");
|
||||
payload.append (instInfo_ptr->suspend_to_str);
|
||||
payload.append ("\",\"resume-to\":\"");
|
||||
payload.append (instInfo_ptr->resume_to_str);
|
||||
payload.append ("\",\"vote-to\":\"");
|
||||
payload.append (instInfo_ptr->vote_to_str);
|
||||
payload.append ("\"");
|
||||
payload.append ("}");
|
||||
|
||||
jlog ("Payload: %s\n", payload.c_str());
|
||||
|
||||
return (payload);
|
||||
}
|
||||
|
||||
int guestUtil_get_inst_info ( string hostname, instInfo * instInfo_ptr, char * buf_ptr )
|
||||
{
|
||||
int rc = PASS ;
|
||||
|
||||
string hostname_str = "" ;
|
||||
string uuid = "" ;
|
||||
string state = "" ;
|
||||
string status = "" ;
|
||||
string restart_to = "" ;
|
||||
string resume_to = "" ;
|
||||
string suspend_to = "" ;
|
||||
string shutdown_to = "" ;
|
||||
string vote_to = "" ;
|
||||
string repair_str = "" ;
|
||||
|
||||
if ( !buf_ptr )
|
||||
{
|
||||
elog ( "null buffer\n" );
|
||||
return ( FAIL_NULL_POINTER );
|
||||
}
|
||||
|
||||
jlog ("Payload: %s\n", buf_ptr );
|
||||
|
||||
int rc0 = jsonUtil_get_key_val ( buf_ptr, "hostname", hostname_str) ;
|
||||
int rc1 = jsonUtil_get_key_val ( buf_ptr, "uuid", uuid ) ;
|
||||
int rc2 = jsonUtil_get_key_val ( buf_ptr, "reporting", state ) ;
|
||||
int rc3 = jsonUtil_get_key_val ( buf_ptr, "heartbeating", status ) ;
|
||||
int rc4 = jsonUtil_get_key_val ( buf_ptr, "restart-to", restart_to ) ;
|
||||
int rc5 = jsonUtil_get_key_val ( buf_ptr, "resume-to", resume_to ) ;
|
||||
int rc6 = jsonUtil_get_key_val ( buf_ptr, "suspend-to", suspend_to ) ;
|
||||
int rc7 = jsonUtil_get_key_val ( buf_ptr, "shutdown-to", shutdown_to ) ;
|
||||
int rc8 = jsonUtil_get_key_val ( buf_ptr, "vote-to", vote_to ) ;
|
||||
int rc9= jsonUtil_get_key_val ( buf_ptr, "repair-action",repair_str ) ;
|
||||
if ( rc0 | rc1 | rc2 | rc3 | rc4 | rc5 | rc6 | rc7 | rc8 | rc9 )
|
||||
{
|
||||
elog ("%s failed parse one or more key values (%d:%d:%d:%d:%d:%d:%d:%d:%d:%d)\n",
|
||||
hostname.c_str(), rc0, rc1, rc2, rc3, rc4, rc5, rc6, rc7, rc8, rc9);
|
||||
|
||||
rc = FAIL_KEY_VALUE_PARSE ;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( hostname.compare(hostname_str) )
|
||||
{
|
||||
wlog ("%s hostname mismatch - loaded\n", hostname_str.c_str());
|
||||
}
|
||||
|
||||
if ( instInfo_ptr )
|
||||
{
|
||||
/* Update the reporting state */
|
||||
if ( !state.compare("enabled") )
|
||||
instInfo_ptr->heartbeat.reporting = true ;
|
||||
else
|
||||
instInfo_ptr->heartbeat.reporting = false ;
|
||||
|
||||
/* update the heartbeating status */
|
||||
if ( !status.compare("enabled") )
|
||||
instInfo_ptr->heartbeating = true ;
|
||||
else
|
||||
instInfo_ptr->heartbeating = false ;
|
||||
|
||||
instInfo_ptr->corrective_action = repair_str ;
|
||||
|
||||
/* Update the intance timeout values */
|
||||
instInfo_ptr->restart_to_str = restart_to ;
|
||||
instInfo_ptr->shutdown_to_str = shutdown_to ;
|
||||
instInfo_ptr->resume_to_str = resume_to ;
|
||||
instInfo_ptr->suspend_to_str = suspend_to ;
|
||||
instInfo_ptr->vote_to_str = vote_to ;
|
||||
}
|
||||
else
|
||||
{
|
||||
wlog ("%s %s lookup failed\n", hostname.c_str(), uuid.c_str());
|
||||
rc = FAIL_INVALID_UUID ;
|
||||
}
|
||||
}
|
||||
return (rc);
|
||||
}
|
||||
|
||||
const char* state_names[] =
|
||||
{
|
||||
"invalid",
|
||||
"server_waiting_init",
|
||||
"server_waiting_challenge",
|
||||
"server_waiting_response",
|
||||
"server_paused",
|
||||
"server_nova_paused",
|
||||
"server_migrating",
|
||||
"server_corrective_action",
|
||||
"client_waiting_init_ack",
|
||||
"client_waiting_challenge",
|
||||
"client_waiting_pause_ack",
|
||||
"client_waiting_resume_ack",
|
||||
"client_paused",
|
||||
"client_waiting_shutdown_ack",
|
||||
"client_waiting_shutdown_response",
|
||||
"client_shutdown_response_recieved",
|
||||
"client_exiting",
|
||||
};
|
||||
|
||||
const char* hb_get_state_name ( hb_state_t s )
|
||||
{
|
||||
if (s >= hbs_state_max)
|
||||
return "???";
|
||||
|
||||
return state_names[s];
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Convert integer to string
|
||||
*****************************************************************************/
|
||||
string int_to_string(int number)
|
||||
{
|
||||
ostringstream ostr;
|
||||
ostr << number;
|
||||
return ostr.str();
|
||||
}
|
||||
|
34
mtce-guest/src/guestUtil.h
Normal file
34
mtce-guest/src/guestUtil.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef __INCLUDE_GUESTUTIL_H__
|
||||
#define __INCLUDE_GUESTUTIL_H__
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
#include "guestBase.h" /* for ... instInfo */
|
||||
|
||||
void guestUtil_inst_init ( instInfo * instance_ptr );
|
||||
void guestUtil_print_instances ( ctrl_type * ctrl_ptr );
|
||||
void guestUtil_print_instance ( instInfo * instInfo_ptr );
|
||||
|
||||
/* called in guestAgent */
|
||||
int guestUtil_get_inst_info ( string hostname, instInfo * instInfo_ptr, char * buf_ptr );
|
||||
|
||||
/* called in guestServer */
|
||||
string guestUtil_set_inst_info ( string hostname, instInfo * instInfo_ptr );
|
||||
|
||||
|
||||
|
||||
string log_prefix ( instInfo * instInfo_ptr );
|
||||
string time_in_secs_to_str ( time_t secs );
|
||||
|
||||
const char* hb_get_corrective_action_name( uint32_t a) ; // heartbeat_corrective_action_t a);
|
||||
const char* hb_get_state_name (hb_state_t s);
|
||||
// Convert integer to string
|
||||
string int_to_string(int number);
|
||||
|
||||
|
||||
#endif /* __INCLUDE_GUESTUTIL_H__ */
|
777
mtce-guest/src/guestVimApi.cpp
Normal file
777
mtce-guest/src/guestVimApi.cpp
Normal file
@ -0,0 +1,777 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2016 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file Wind River CGTS Platform Guest Heartbeat REST API
|
||||
* used to report heartbeat faults or query instance
|
||||
* information from the VIM.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __AREA__
|
||||
#undef __AREA__
|
||||
#endif
|
||||
#define __AREA__ "vim"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "nodeBase.h" /* for ... common definitions */
|
||||
#include "nodeUtil.h" /* for ... common utilities */
|
||||
#include "jsonUtil.h" /* for ... jsonUtil_get_key_val */
|
||||
|
||||
#include "guestUtil.h" /* for ... guestUtil_inst_init */
|
||||
#include "guestSvrUtil.h" /* for ... hb_get_corrective_action_name */
|
||||
#include "guestVimApi.h" /* for ... this module header */
|
||||
|
||||
#define URL_VIM_ADDRESS "127.0.0.1"
|
||||
#define URL_VIM_INST_LABEL "/nfvi-plugins/v1/instances/"
|
||||
#define URL_VIM_HOST_LABEL "/nfvi-plugins/v1/hosts/"
|
||||
|
||||
#define VIM_EVENT_SIG "vimEvent"
|
||||
#define VIM_SIG "vim"
|
||||
|
||||
#define OPER__HOST_STATE_QUERY "host state query"
|
||||
#define OPER__HOST_INST_QUERY "host inst query"
|
||||
#define OPER__HOST_INST_FAIL "host inst fail"
|
||||
#define OPER__HOST_INST_STATUS "host inst status"
|
||||
#define OPER__HOST_INST_CHANGE "inst status change"
|
||||
#define OPER__HOST_INST_NOTIFY "host inst notify"
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Name : guestVimApi_handler
|
||||
*
|
||||
* Description: The Guest Heartbeat event request handler
|
||||
*
|
||||
*********************************************************************/
|
||||
void guestHostClass::guestVimApi_handler ( struct evhttp_request *req, void *arg )
|
||||
{
|
||||
string hostname = "unknown" ;
|
||||
|
||||
guestHostClass * obj_ptr = get_hostInv_ptr();
|
||||
libEvent & event = obj_ptr->getEvent ( (struct event_base *)arg, hostname );
|
||||
if ( event.request == SERVICE_NONE )
|
||||
{
|
||||
slog ("guest instance Lookup Failed (%p)\n", arg);
|
||||
return ;
|
||||
}
|
||||
|
||||
/* Check for command timeout */
|
||||
if ( !req )
|
||||
{
|
||||
dlog ("hostname=%s service=%s No Request Parm (%s)\n",
|
||||
event.hostname.c_str(),
|
||||
event.service.c_str(),
|
||||
event.uuid.c_str());
|
||||
}
|
||||
|
||||
/* Check the HTTP Status Code */
|
||||
event.status = guestHttpUtil_status ( event ) ;
|
||||
if ( event.status == HTTP_NOTFOUND )
|
||||
{
|
||||
wlog ("%s Not Found (%d)\n", event.log_prefix.c_str(),
|
||||
event.status);
|
||||
goto _guest_handler_done ;
|
||||
}
|
||||
|
||||
else if ( event.status != PASS )
|
||||
{
|
||||
/* The VIM Might not be running at he time I issue the query.
|
||||
* In hat case I will get back a 400 */
|
||||
if (( event.request != VIM_HOST_STATE_QUERY ) && ( event.status != 400 ))
|
||||
{
|
||||
elog ("%s HTTP Request Failed (%d) (%s)\n",
|
||||
event.log_prefix.c_str(),
|
||||
event.status,
|
||||
event.uuid.c_str());
|
||||
}
|
||||
goto _guest_handler_done ;
|
||||
}
|
||||
|
||||
/* No response content for this command */
|
||||
if ( event.request == VIM_HOST_INSTANCE_STATUS )
|
||||
{
|
||||
jlog ("%s %s instance status change succeeded\n", event.hostname.c_str(), event.uuid.c_str());
|
||||
goto _guest_handler_done ;
|
||||
}
|
||||
|
||||
/* No response content for this command */
|
||||
else if ( event.request == VIM_HOST_INSTANCE_NOTIFY )
|
||||
{
|
||||
jlog ("%s %s instance notify succeeded\n", event.hostname.c_str(), event.uuid.c_str());
|
||||
goto _guest_handler_done ;
|
||||
}
|
||||
|
||||
else if ( httpUtil_get_response ( event ) != PASS )
|
||||
{
|
||||
wlog ("%s no response available\n", hostname.c_str());
|
||||
goto _guest_handler_done ;
|
||||
}
|
||||
|
||||
if ( event.response.length() )
|
||||
{
|
||||
jlog ("%s Response: %s\n", event.hostname.c_str(),
|
||||
event.response.c_str());
|
||||
|
||||
if ( event.request == VIM_HOST_STATE_QUERY )
|
||||
{
|
||||
ilog ("%s host state query response\n", event.hostname.c_str());
|
||||
int rc = jsonUtil_get_key_val ( (char*)event.response.data(), "state", event.value ) ;
|
||||
if ( rc != PASS )
|
||||
{
|
||||
elog ("failed to state value (rc=%d)\n", rc );
|
||||
event.status = FAIL_KEY_VALUE_PARSE ;
|
||||
event.value = "disabled" ; /* override to disabled if operation failed */
|
||||
}
|
||||
}
|
||||
|
||||
else if ( event.request == VIM_HOST_INSTANCE_FAILED )
|
||||
{
|
||||
ilog ("%s instance failure response\n", event.uuid.c_str());
|
||||
// {"services": [ {"state": "enabled", "service": "heartbeat"}],
|
||||
// "hostname": "compute-1",
|
||||
// "uuid": "da973c2a-7469-4e06-b7e1-89bf2643f906"}
|
||||
string state = "" ;
|
||||
string service = "" ;
|
||||
string uuid = "" ;
|
||||
int rc1 = jsonUtil_get_key_val ( (char*)event.response.data(), "hostname", hostname ) ;
|
||||
int rc2 = jsonUtil_get_key_val ( (char*)event.response.data(), "uuid" , uuid ) ;
|
||||
if (!(rc1 | rc2 ))
|
||||
{
|
||||
/* Look for the list of services for this instance
|
||||
* - currently only heartbeat is supported
|
||||
*
|
||||
* services:[ { "state": "enabled", "service": "heartbeat" } ]
|
||||
*/
|
||||
string service_list = "" ;
|
||||
rc1 = jsonUtil_get_array_idx ((char*)event.response.data(), "services", 0, service_list ) ;
|
||||
if ( rc1 == PASS )
|
||||
{
|
||||
instInfo instance ; guestUtil_inst_init ( &instance );
|
||||
guestHostClass * obj_ptr = get_hostInv_ptr();
|
||||
string service = "" ;
|
||||
|
||||
ilog ("Service List:%s\n", service_list.c_str()); // jlog1
|
||||
|
||||
instance.uuid = uuid ;
|
||||
|
||||
/* Get the contents of the services list/array
|
||||
* Note: we only support one element of the array so hat's
|
||||
* why only index 0 is being requested or looked for
|
||||
*
|
||||
* Get the state of the only service - heartbeat */
|
||||
rc1 = jsonUtil_get_key_val ( (char*)service_list.data(), "state", instance.heartbeat.state ) ;
|
||||
rc2 = jsonUtil_get_key_val ( (char*)service_list.data(), "service", service ) ;
|
||||
|
||||
/* both of these must pass in order to add this instance */
|
||||
if (( rc1 == PASS ) && ( rc2 == PASS ))
|
||||
{
|
||||
if ( !service.compare("heartbeat") )
|
||||
{
|
||||
instance.heartbeat.provisioned = true ;
|
||||
|
||||
/* Its either enabled or disabled
|
||||
* - default was disabled in guestUtil_inst_init above */
|
||||
if ( !instance.heartbeat.state.compare("enabled") )
|
||||
{
|
||||
instance.heartbeat.reporting = true ;
|
||||
rc1 = obj_ptr->mod_inst ( hostname, instance );
|
||||
}
|
||||
else if ( !instance.heartbeat.state.compare("disabled") )
|
||||
{
|
||||
instance.heartbeat.reporting = false ;
|
||||
rc1 = obj_ptr->mod_inst ( hostname, instance );
|
||||
}
|
||||
else
|
||||
{
|
||||
// raise error if it is neither enabled nor disabled
|
||||
elog ("%s %s invalid heartbeat.state value %s received\n",
|
||||
hostname.c_str(), instance.uuid.c_str(), instance.heartbeat.state.c_str());
|
||||
event.status = FAIL_INVALID_DATA ;
|
||||
rc1 = FAIL;
|
||||
}
|
||||
if ( rc1 == PASS )
|
||||
{
|
||||
/* o.K. so its provisioned !! */
|
||||
dlog ("%s %s instance modified\n", hostname.c_str(), instance.uuid.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
event.status = rc1 ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
elog ("%s unsupported 'service' (%s)\n", hostname.c_str(), service.c_str() );
|
||||
event.status = FAIL_INVALID_DATA ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
elog ("%s failed to get 'state' or 'service' (%d:%d)\n", hostname.c_str(), rc1, rc2 );
|
||||
event.status = FAIL_KEY_VALUE_PARSE ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
elog ("%s failed to get 'service list' or 'uuid' (%d:%d)\n", hostname.c_str(), rc1, rc2 );
|
||||
event.status = FAIL_KEY_VALUE_PARSE ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ilog ("%s failed to get 'hostname' or 'uuid' (%d:%d)\n", event.hostname.c_str(), rc1, rc2 );
|
||||
event.status = FAIL_KEY_VALUE_PARSE ;
|
||||
}
|
||||
}
|
||||
else if ( event.request == VIM_HOST_INSTANCE_QUERY )
|
||||
{
|
||||
ilog ("%s instance query response\n", event.uuid.c_str());
|
||||
/* { "instances": [{"services": {"service":"heartbeat", "state":"enabled"},
|
||||
* "hostname": "compute-2",
|
||||
* "uuid": "3aca8dad-0e38-4a58-83ab-23ee71159e0d"}]} */
|
||||
|
||||
int rc = jsonUtil_get_key_val ( (char*)event.response.data(), "instances", event.value ) ;
|
||||
if ( rc != PASS )
|
||||
{
|
||||
elog ("%s failed to get host instance array (rc=%d) (%s)\n",
|
||||
event.hostname.c_str(), rc, event.uuid.c_str());
|
||||
event.status = FAIL_KEY_VALUE_PARSE ;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The following code parses a JSON string that looks like this.
|
||||
* {
|
||||
* "instances":
|
||||
* [
|
||||
* { "services": { "service":"heartbeat", "state":"enabled" },
|
||||
* "hostname": "compute-2",
|
||||
* "uuid" : "3aca8dad-0e38-4a58-83ab-23ee71159e0d"
|
||||
* }
|
||||
* ] , ...
|
||||
* }
|
||||
*/
|
||||
int instances = 0 ;
|
||||
jlog ("%s instance array %s\n", event.hostname.c_str(), (char*)event.response.data());
|
||||
rc = jsonUtil_array_elements ( (char*)event.response.data(), "instances", instances );
|
||||
if ( rc != PASS )
|
||||
{
|
||||
elog ("%s failed to get array elements (%d)\n", hostname.c_str(), rc );
|
||||
event.status = FAIL_KEY_VALUE_PARSE ;
|
||||
}
|
||||
else
|
||||
{
|
||||
ilog ("%s has %d instances\n", hostname.c_str(), instances );
|
||||
for ( int i = 0 ; i < instances ; i++ )
|
||||
{
|
||||
string instance_element = "" ;
|
||||
rc = jsonUtil_get_array_idx ( (char*)event.response.data(), "instances", i, instance_element );
|
||||
if ( ( rc == PASS ) && ( instance_element.size() ))
|
||||
{
|
||||
/* Look for the list of services for this instance
|
||||
* - currently only heartbeat is supported
|
||||
*
|
||||
* services:[ { "state": "enabled", "service": "heartbeat" } ]
|
||||
**/
|
||||
string service_list = "" ;
|
||||
string uuid = "" ;
|
||||
int rc1 = jsonUtil_get_array_idx ((char*)instance_element.data(), "services", 0, service_list ) ;
|
||||
int rc2 = jsonUtil_get_key_val ((char*)instance_element.data(), "uuid", uuid ) ;
|
||||
if (( rc1 == PASS ) && ( rc2 == PASS ))
|
||||
{
|
||||
instInfo instance ; guestUtil_inst_init ( &instance );
|
||||
guestHostClass * obj_ptr = get_hostInv_ptr();
|
||||
string service = "" ;
|
||||
|
||||
ilog ("Service List:%s\n", service_list.c_str());
|
||||
|
||||
instance.uuid = uuid ;
|
||||
|
||||
/* Get the contents of the services list/array
|
||||
* Note: we only support one element of the array so hat's
|
||||
* why only index 0 is being requested or looked for
|
||||
*
|
||||
* Get the state of the only service - heartbeat */
|
||||
rc1 = jsonUtil_get_key_val ( (char*)service_list.data(), "state", instance.heartbeat.state ) ;
|
||||
rc2 = jsonUtil_get_key_val ( (char*)service_list.data(), "service", service ) ;
|
||||
|
||||
/* both of these must pass in order to add this instance */
|
||||
if (( rc1 == PASS ) && ( rc2 == PASS ))
|
||||
{
|
||||
if ( !service.compare("heartbeat") )
|
||||
{
|
||||
instance.heartbeat.provisioned = true ;
|
||||
|
||||
/* Its either enabled or disabled
|
||||
* - default was disabled in guestUtil_inst_init above */
|
||||
if ( !instance.heartbeat.state.compare("enabled") )
|
||||
{
|
||||
instance.heartbeat.reporting = true ;
|
||||
rc = obj_ptr->add_inst ( hostname, instance );
|
||||
}
|
||||
else if ( !instance.heartbeat.state.compare("disabled") )
|
||||
{
|
||||
instance.heartbeat.reporting = false ;
|
||||
rc = obj_ptr->add_inst ( hostname, instance );
|
||||
}
|
||||
else
|
||||
{
|
||||
// raise error if it is neither enabled nor disabled
|
||||
elog ("%s %s invalid heartbeat.state value %s received\n",
|
||||
hostname.c_str(), instance.uuid.c_str(), instance.heartbeat.state.c_str());
|
||||
event.status = FAIL_INVALID_DATA ;
|
||||
rc = FAIL;
|
||||
}
|
||||
if ( rc == PASS )
|
||||
{
|
||||
/* o.K. so its provisioned !! */
|
||||
ilog ("%s %s instance added\n", hostname.c_str(), instance.uuid.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
event.status = rc ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
elog ("%s unsupported 'service' (%s)\n", hostname.c_str(), service.c_str() );
|
||||
event.status = FAIL_INVALID_DATA ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
elog ("%s failed to get 'state' or 'service' (%d:%d)\n", hostname.c_str(), rc1, rc2 );
|
||||
wlog ("... Service List: %s\n", service_list.data());
|
||||
event.status = FAIL_KEY_VALUE_PARSE ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
elog ("%s failed to get 'service list' or 'uuid' (%d:%d)\n", hostname.c_str(), rc1, rc2 );
|
||||
event.status = FAIL_KEY_VALUE_PARSE ;
|
||||
}
|
||||
}
|
||||
else if ( rc != PASS )
|
||||
{
|
||||
elog ("%s failed to get array index %d (rc=%d)\n", hostname.c_str(), i, rc );
|
||||
event.status = FAIL_KEY_VALUE_PARSE ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_guest_handler_done:
|
||||
|
||||
// httpUtil_log_event ( event );
|
||||
|
||||
if (( event.request != SERVICE_NONE ) &&
|
||||
( event.status != HTTP_OK ) &&
|
||||
( event.status != PASS ))
|
||||
{
|
||||
// wlog ("Event Status: %d\n", event.status );
|
||||
|
||||
/* TODO: Enable log_event */
|
||||
wlog ("%s Address : %s (%d)\n",
|
||||
event.log_prefix.c_str(),
|
||||
event.address.c_str(),
|
||||
event.status);
|
||||
elog ("%s Payload : %s\n", event.log_prefix.c_str(), event.payload.c_str());
|
||||
if ( event.response.size() )
|
||||
{
|
||||
elog ("%s Response: %s\n", event.log_prefix.c_str(), event.response.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
elog ("%s: no response\n", event.log_prefix.c_str());
|
||||
}
|
||||
}
|
||||
event.active = false ;
|
||||
httpUtil_free_conn ( event );
|
||||
httpUtil_free_base ( event );
|
||||
|
||||
/* This is needed to get out of the loop */
|
||||
event_base_loopbreak((struct event_base *)arg);
|
||||
}
|
||||
|
||||
/* The Guest Heartbeat event request handler
|
||||
* wrapper abstracted from guestHostClass */
|
||||
void guestVimApi_Handler ( struct evhttp_request *req, void *arg )
|
||||
{
|
||||
get_hostInv_ptr()->guestVimApi_handler ( req , arg );
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : guestVimApi_svc_event
|
||||
*
|
||||
* Description: Send a VM instance service state/status change notification
|
||||
* to the VIM.
|
||||
*
|
||||
* Warning : Only the 'heartbeat' service 'status' change is supported.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
int guestVimApi_svc_event ( string hostname,
|
||||
string instance_uuid,
|
||||
string state,
|
||||
string status,
|
||||
string timeout)
|
||||
{
|
||||
guestHostClass * obj_ptr = get_hostInv_ptr() ;
|
||||
|
||||
ilog ("%s %s %s heartbeating status change to '%s' (to vim)\n", hostname.c_str(),
|
||||
instance_uuid.c_str(),
|
||||
state.c_str(),
|
||||
status.c_str());
|
||||
|
||||
instInfo * instInfo_ptr = obj_ptr->get_inst ( instance_uuid );
|
||||
if ( instInfo_ptr )
|
||||
{
|
||||
httpUtil_event_init ( &instInfo_ptr->vimEvent,
|
||||
hostname,
|
||||
VIM_SIG,
|
||||
URL_VIM_ADDRESS,
|
||||
daemon_get_cfg_ptr()->vim_event_port);
|
||||
|
||||
instInfo_ptr->vimEvent.base = NULL ;
|
||||
instInfo_ptr->vimEvent.conn = NULL ;
|
||||
|
||||
/* Set the host context */
|
||||
instInfo_ptr->vimEvent.uuid = instance_uuid ;
|
||||
instInfo_ptr->vimEvent.cur_retries = 0 ;
|
||||
instInfo_ptr->vimEvent.max_retries = 3 ;
|
||||
instInfo_ptr->vimEvent.active = true ;
|
||||
instInfo_ptr->vimEvent.noncritical = false ;
|
||||
|
||||
instInfo_ptr->vimEvent.request = VIM_HOST_INSTANCE_STATUS;
|
||||
instInfo_ptr->vimEvent.operation = OPER__HOST_INST_CHANGE ;
|
||||
instInfo_ptr->vimEvent.token.url = URL_VIM_INST_LABEL ;
|
||||
instInfo_ptr->vimEvent.token.url.append(instance_uuid) ;
|
||||
|
||||
/* The type of HTTP request */
|
||||
instInfo_ptr->vimEvent.type = EVHTTP_REQ_PATCH ;
|
||||
|
||||
/* Build the payload */
|
||||
instInfo_ptr->vimEvent.payload = ("{\"uuid\":\"");
|
||||
instInfo_ptr->vimEvent.payload.append (instance_uuid);
|
||||
instInfo_ptr->vimEvent.payload.append ("\",\"hostname\":\"");
|
||||
instInfo_ptr->vimEvent.payload.append (hostname);
|
||||
instInfo_ptr->vimEvent.payload.append ("\",\"event-type\":\"service\",\"event-data\":{\"services\":");
|
||||
instInfo_ptr->vimEvent.payload.append ("[{\"service\":\"heartbeat\",\"state\":\"");
|
||||
instInfo_ptr->vimEvent.payload.append (state);
|
||||
instInfo_ptr->vimEvent.payload.append ("\",\"status\":\"");
|
||||
instInfo_ptr->vimEvent.payload.append (status);
|
||||
instInfo_ptr->vimEvent.payload.append ("\",\"restart-timeout\":\"");
|
||||
instInfo_ptr->vimEvent.payload.append (timeout);
|
||||
instInfo_ptr->vimEvent.payload.append ("\"}]}}");
|
||||
|
||||
jlog ("%s %s Payload: %s\n", hostname.c_str(), instance_uuid.c_str(), instInfo_ptr->vimEvent.payload.c_str());
|
||||
|
||||
return (guestHttpUtil_api_req ( instInfo_ptr->vimEvent ));
|
||||
}
|
||||
return (FAIL_HOSTNAME_LOOKUP);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : guestVimApi_alarm_event
|
||||
*
|
||||
* Description: Send a VM instance service an alarm event.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
int guestVimApi_alarm_event ( string hostname,
|
||||
string instance_uuid)
|
||||
{
|
||||
guestHostClass * obj_ptr = get_hostInv_ptr() ;
|
||||
|
||||
ilog ("%s %s heartbeating alarm (ill health) event (to vim)\n",
|
||||
hostname.c_str(),
|
||||
instance_uuid.c_str());
|
||||
|
||||
instInfo * instInfo_ptr = obj_ptr->get_inst ( instance_uuid );
|
||||
if ( instInfo_ptr )
|
||||
{
|
||||
httpUtil_event_init ( &instInfo_ptr->vimEvent,
|
||||
hostname,
|
||||
VIM_SIG,
|
||||
URL_VIM_ADDRESS,
|
||||
daemon_get_cfg_ptr()->vim_event_port);
|
||||
|
||||
instInfo_ptr->vimEvent.base = NULL ;
|
||||
instInfo_ptr->vimEvent.conn = NULL ;
|
||||
|
||||
/* Set the host context */
|
||||
instInfo_ptr->vimEvent.uuid = instance_uuid ;
|
||||
instInfo_ptr->vimEvent.cur_retries = 0 ;
|
||||
instInfo_ptr->vimEvent.max_retries = 3 ;
|
||||
instInfo_ptr->vimEvent.active = true ;
|
||||
instInfo_ptr->vimEvent.noncritical = false ;
|
||||
|
||||
instInfo_ptr->vimEvent.request = VIM_HOST_INSTANCE_STATUS;
|
||||
instInfo_ptr->vimEvent.operation = OPER__HOST_INST_CHANGE ;
|
||||
instInfo_ptr->vimEvent.token.url = URL_VIM_INST_LABEL ;
|
||||
instInfo_ptr->vimEvent.token.url.append(instance_uuid) ;
|
||||
|
||||
/* The type of HTTP request */
|
||||
instInfo_ptr->vimEvent.type = EVHTTP_REQ_PATCH ;
|
||||
|
||||
/* Build the payload */
|
||||
instInfo_ptr->vimEvent.payload = ("{\"uuid\":\"");
|
||||
instInfo_ptr->vimEvent.payload.append (instance_uuid);
|
||||
instInfo_ptr->vimEvent.payload.append ("\",\"hostname\":\"");
|
||||
instInfo_ptr->vimEvent.payload.append (hostname);
|
||||
|
||||
instInfo_ptr->vimEvent.payload.append ("\",\"event-type\":\"alarm\",\"event-data\":{\"services\":");
|
||||
instInfo_ptr->vimEvent.payload.append ("[{\"service\":\"heartbeat\",\"state\":\"unhealthy\",\"repair-action\":\"");
|
||||
instInfo_ptr->vimEvent.payload.append (instInfo_ptr->corrective_action);
|
||||
instInfo_ptr->vimEvent.payload.append ("\"}]}}");
|
||||
|
||||
jlog ("%s %s Payload: %s\n", hostname.c_str(),
|
||||
instance_uuid.c_str(),
|
||||
instInfo_ptr->vimEvent.payload.c_str());
|
||||
|
||||
return (guestHttpUtil_api_req ( instInfo_ptr->vimEvent ));
|
||||
}
|
||||
return (FAIL_HOSTNAME_LOOKUP);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : guestVimApi_inst_failed
|
||||
*
|
||||
* Description: Send a VM instance a failure notification to the VIM.
|
||||
*
|
||||
* Supported failures are ...
|
||||
*
|
||||
* MTC_EVENT_HEARTBEAT_LOSS
|
||||
*
|
||||
*****************************************************************************/
|
||||
int guestVimApi_inst_failed ( string hostname,
|
||||
string instance_uuid,
|
||||
unsigned int event,
|
||||
int retries )
|
||||
{
|
||||
guestHostClass * obj_ptr = get_hostInv_ptr() ;
|
||||
|
||||
elog ("%s %s *** Heartbeat Loss *** \n",
|
||||
hostname.c_str(),
|
||||
instance_uuid.c_str() );
|
||||
|
||||
if ( obj_ptr->get_reporting_state (hostname) == false )
|
||||
{
|
||||
ilog ("%s cancelling failure notification request\n", hostname.c_str());
|
||||
ilog ("%s ... 'host' level fault reporting is disabled\n", hostname.c_str());
|
||||
return (PASS);
|
||||
}
|
||||
instInfo * instInfo_ptr = obj_ptr->get_inst ( instance_uuid );
|
||||
if ( instInfo_ptr )
|
||||
{
|
||||
if (( event == MTC_EVENT_HEARTBEAT_LOSS ) &&
|
||||
( instInfo_ptr->heartbeat.reporting == false ))
|
||||
{
|
||||
ilog ("%s cancelling failure notification request\n", hostname.c_str());
|
||||
ilog ("%s ... 'instance' level fault reporting is disabled\n", hostname.c_str());
|
||||
return (PASS);
|
||||
}
|
||||
|
||||
httpUtil_event_init ( &instInfo_ptr->vimEvent,
|
||||
hostname,
|
||||
VIM_SIG,
|
||||
URL_VIM_ADDRESS,
|
||||
daemon_get_cfg_ptr()->vim_event_port);
|
||||
|
||||
instInfo_ptr->vimEvent.base = NULL ;
|
||||
instInfo_ptr->vimEvent.conn = NULL ;
|
||||
|
||||
/* Set the host context */
|
||||
instInfo_ptr->vimEvent.uuid = instance_uuid ;
|
||||
instInfo_ptr->vimEvent.cur_retries = 0 ;
|
||||
instInfo_ptr->vimEvent.max_retries = retries ;
|
||||
instInfo_ptr->vimEvent.active = true ;
|
||||
instInfo_ptr->vimEvent.noncritical = false ;
|
||||
|
||||
instInfo_ptr->vimEvent.request = VIM_HOST_INSTANCE_FAILED;
|
||||
instInfo_ptr->vimEvent.operation = OPER__HOST_INST_FAIL ;
|
||||
instInfo_ptr->vimEvent.token.url = URL_VIM_INST_LABEL ;
|
||||
instInfo_ptr->vimEvent.token.url.append(instance_uuid) ;
|
||||
|
||||
/* The type of HTTP request */
|
||||
instInfo_ptr->vimEvent.type = EVHTTP_REQ_PATCH ;
|
||||
|
||||
/* Build the payload */
|
||||
instInfo_ptr->vimEvent.payload = ("{\"uuid\":\"");
|
||||
instInfo_ptr->vimEvent.payload.append (instance_uuid);
|
||||
instInfo_ptr->vimEvent.payload.append ("\",\"hostname\":\"");
|
||||
instInfo_ptr->vimEvent.payload.append (hostname);
|
||||
if ( event == MTC_EVENT_HEARTBEAT_LOSS )
|
||||
{
|
||||
instInfo_ptr->vimEvent.payload.append ("\",\"event-type\":\"alarm\",\"event-data\":{\"services\":");
|
||||
instInfo_ptr->vimEvent.payload.append ("[{\"service\":\"heartbeat\",\"state\":\"failed\",\"repair-action\":\"");
|
||||
instInfo_ptr->vimEvent.payload.append (instInfo_ptr->corrective_action);
|
||||
instInfo_ptr->vimEvent.payload.append ("\"}]}}");
|
||||
|
||||
wlog ("%s %s Payload: %s\n", hostname.c_str(),
|
||||
instance_uuid.c_str(),
|
||||
instInfo_ptr->vimEvent.payload.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
elog ("%s Unsupported 'event code' (%d)\n", instance_uuid.c_str(), event );
|
||||
return (FAIL_BAD_PARM);
|
||||
}
|
||||
|
||||
return (guestHttpUtil_api_req ( instInfo_ptr->vimEvent ));
|
||||
}
|
||||
return (FAIL_HOSTNAME_LOOKUP);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : guestVimApi_inst_action
|
||||
*
|
||||
* Description: Send a notify message to the VIM in response to voting or notification
|
||||
*
|
||||
*****************************************************************************/
|
||||
int guestVimApi_inst_action ( string hostname,
|
||||
string instance_uuid,
|
||||
string action,
|
||||
string guest_response,
|
||||
string reason,
|
||||
int retries)
|
||||
{
|
||||
guestHostClass * obj_ptr = get_hostInv_ptr() ;
|
||||
|
||||
ilog ("%s %s '%s' action (to vim)\n", hostname.c_str(), instance_uuid.c_str() , action.c_str() );
|
||||
|
||||
instInfo * instInfo_ptr = obj_ptr->get_inst ( instance_uuid );
|
||||
if ( !instInfo_ptr )
|
||||
return FAIL_HOSTNAME_LOOKUP;
|
||||
|
||||
httpUtil_event_init ( &instInfo_ptr->vimEvent,
|
||||
hostname,
|
||||
VIM_SIG,
|
||||
URL_VIM_ADDRESS,
|
||||
daemon_get_cfg_ptr()->vim_event_port);
|
||||
|
||||
instInfo_ptr->vimEvent.base = NULL ;
|
||||
instInfo_ptr->vimEvent.conn = NULL ;
|
||||
|
||||
/* Set the host context */
|
||||
instInfo_ptr->vimEvent.uuid = instance_uuid ;
|
||||
instInfo_ptr->vimEvent.cur_retries = 0 ;
|
||||
instInfo_ptr->vimEvent.max_retries = retries ;
|
||||
instInfo_ptr->vimEvent.active = true ;
|
||||
instInfo_ptr->vimEvent.noncritical = false ;
|
||||
|
||||
instInfo_ptr->vimEvent.request = VIM_HOST_INSTANCE_NOTIFY;
|
||||
instInfo_ptr->vimEvent.operation = OPER__HOST_INST_NOTIFY ;
|
||||
instInfo_ptr->vimEvent.token.url = URL_VIM_INST_LABEL ;
|
||||
instInfo_ptr->vimEvent.token.url.append(instance_uuid) ;
|
||||
|
||||
/* The type of HTTP request */
|
||||
instInfo_ptr->vimEvent.type = EVHTTP_REQ_PATCH ;
|
||||
|
||||
/* Build the payload */
|
||||
instInfo_ptr->vimEvent.payload = ("{\"uuid\":\"");
|
||||
instInfo_ptr->vimEvent.payload.append (instance_uuid);
|
||||
instInfo_ptr->vimEvent.payload.append ("\",\"event-type\": \"action\",\"event-data\": {\"action\": \"");
|
||||
instInfo_ptr->vimEvent.payload.append (action);
|
||||
instInfo_ptr->vimEvent.payload.append ("\", \"guest-response\": \"");
|
||||
instInfo_ptr->vimEvent.payload.append (guest_response);
|
||||
instInfo_ptr->vimEvent.payload.append ("\", \"reason\": \"");
|
||||
instInfo_ptr->vimEvent.payload.append (jsonUtil_escapeSpecialChar(reason));
|
||||
instInfo_ptr->vimEvent.payload.append ("\"}}");
|
||||
|
||||
jlog ("%s %s Payload: %s\n", hostname.c_str(), instance_uuid.c_str(), instInfo_ptr->vimEvent.payload.c_str());
|
||||
|
||||
return (guestHttpUtil_api_req ( instInfo_ptr->vimEvent ));
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : guestVimApi_getHostState
|
||||
*
|
||||
* Description: Ask the VIM for the top level fault reporting
|
||||
* state for this host
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
int guestVimApi_getHostState ( string hostname, string uuid, libEvent & event )
|
||||
{
|
||||
httpUtil_event_init ( &event,
|
||||
hostname,
|
||||
VIM_SIG,
|
||||
URL_VIM_ADDRESS,
|
||||
daemon_get_cfg_ptr()->vim_event_port);
|
||||
|
||||
event.base = NULL ;
|
||||
event.conn = NULL ;
|
||||
event.uuid = uuid ;
|
||||
event.active = true ;
|
||||
event.noncritical = false ;
|
||||
|
||||
event.type = EVHTTP_REQ_GET ;
|
||||
event.request = VIM_HOST_STATE_QUERY;
|
||||
event.operation = OPER__HOST_STATE_QUERY ;
|
||||
event.token.url = URL_VIM_HOST_LABEL ;
|
||||
event.token.url.append(event.uuid);
|
||||
|
||||
/* Build the payload */
|
||||
event.payload = "{\"hostname\": \"";
|
||||
event.payload.append (hostname) ;
|
||||
event.payload.append ("\",\"uuid\":\"");
|
||||
event.payload.append (uuid);
|
||||
event.payload.append ("\"}");
|
||||
|
||||
jlog ("%s %s Payload: %s\n", hostname.c_str(), uuid.c_str(), event.payload.c_str());
|
||||
|
||||
return ( guestHttpUtil_api_req ( event ) );
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : guestVimApi_getHostInst
|
||||
*
|
||||
* Description: Ask the VIM for all the VM instance info for the
|
||||
* specified host.
|
||||
*
|
||||
*****************************************************************************/
|
||||
int guestVimApi_getHostInst ( string hostname, string uuid, libEvent & event )
|
||||
{
|
||||
httpUtil_event_init ( &event,
|
||||
hostname,
|
||||
VIM_SIG,
|
||||
URL_VIM_ADDRESS,
|
||||
daemon_get_cfg_ptr()->vim_event_port);
|
||||
|
||||
event.base = NULL ;
|
||||
event.conn = NULL ;
|
||||
event.uuid = uuid ;
|
||||
event.active = true ;
|
||||
event.noncritical = false ;
|
||||
|
||||
event.type = EVHTTP_REQ_GET ;
|
||||
event.request = VIM_HOST_INSTANCE_QUERY;
|
||||
event.operation = OPER__HOST_INST_QUERY ;
|
||||
event.token.url = URL_VIM_INST_LABEL ;
|
||||
event.token.url.append("?host_uuid=");
|
||||
event.token.url.append(event.uuid);
|
||||
|
||||
jlog ("%s %s Payload: %s\n", hostname.c_str(), event.uuid.c_str(), event.token.url.c_str());
|
||||
|
||||
return ( guestHttpUtil_api_req ( event ) );
|
||||
}
|
47
mtce-guest/src/guestVimApi.h
Normal file
47
mtce-guest/src/guestVimApi.h
Normal file
@ -0,0 +1,47 @@
|
||||
#ifndef __INCLUDE_GUESTVIMAPI_H__
|
||||
#define __INCLUDE_GUESTVIMAPI_H__
|
||||
/*
|
||||
* Copyright (c) 2013, 2015 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "guestHttpUtil.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Wind River CGTS Platform Guest Services Request Transmitter.
|
||||
*
|
||||
* This module is used by the guestAgent only and allows the guestAgent to
|
||||
*
|
||||
* 1. Transmit notification of an instance failure to the VIM
|
||||
*
|
||||
* guestVimApi_inst_failed
|
||||
*
|
||||
* 2. Get the instrance info for a specified host from the VIM
|
||||
*
|
||||
* guestVimApi_getHostState
|
||||
*
|
||||
* 3. Get the host level fault reporting state.
|
||||
*
|
||||
* guestVimApi_getHostInst
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
int guestVimApi_init ( string ip, int port );
|
||||
void guestVimApi_fini ( void );
|
||||
|
||||
int guestVimApi_inst_failed ( string hostname, string instance, unsigned int event, int retries );
|
||||
int guestVimApi_inst_action ( string hostname, string instance_uuid, string action, string guest_response, string reason, int retries=0 );
|
||||
int guestVimApi_svc_event ( string hostname, string instance_uuid, string state, string status, string timeout );
|
||||
int guestVimApi_alarm_event ( string hostname, string instance_uuid );
|
||||
int guestVimApi_getHostInst ( string hostname, string uuid, libEvent & event );
|
||||
int guestVimApi_getHostState ( string hostname, string uuid, libEvent & event );
|
||||
|
||||
void guestVimApi_Handler ( struct evhttp_request *req, void *arg );
|
||||
|
||||
#endif /* __INCLUDE_GUESTVIMAPI_H__ */
|
373
mtce-guest/src/guestVirtio.cpp
Normal file
373
mtce-guest/src/guestVirtio.cpp
Normal file
@ -0,0 +1,373 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2015 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <execinfo.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <netdb.h>
|
||||
#include <poll.h>
|
||||
#include <resolv.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "nodeBase.h"
|
||||
#include "nodeEvent.h"
|
||||
#include "guestBase.h"
|
||||
#include "guestUtil.h"
|
||||
#include "guestVirtio.h"
|
||||
#include "guestInstClass.h" /* for ... get_inst */
|
||||
|
||||
/*****************************************************************************
|
||||
* Name : virtio_check_filename
|
||||
*
|
||||
* Purpose: Return valid virtio instance heartbeat messaging socket filenames
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Check a filename, already striped of an directory component,
|
||||
* against the expected pattern for a cgcs heartbeat vio socket file.
|
||||
*
|
||||
* If satisfied, returns an allocated buffer containing the qemu instance name.
|
||||
* The buffer must be free'd.
|
||||
*
|
||||
* Returns NULL on failure.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
const char* host_virtio_dir = "/var/lib/libvirt/qemu";
|
||||
|
||||
// Use instance id to substitute the first %s below
|
||||
const char* host_virtio_file_format_print = "cgcs.heartbeat.%s.sock";
|
||||
const char* alt_host_virtio_file_format_print = "wrs.heartbeat.agent.0.%s.sock";
|
||||
|
||||
// Must return '2' when scaned, first buffer recieves instance id, second should get a k, and third is unused
|
||||
const char* virtio_file_format_scan = "%m[cgcs].%m[heartbeat].%m[^.].soc%m[k]%ms";
|
||||
const char* host_virtio_file_format_scan = "cgcs.heartbeat.%m[^.].soc%m[k]%ms";
|
||||
const char* alt_host_virtio_file_format_scan = "wrs.heartbeat.agent.0.%m[^.].soc%m[k]%ms";
|
||||
|
||||
string virtio_instance_name ( char * fn )
|
||||
{
|
||||
string name = "" ;
|
||||
char *s1 = NULL;
|
||||
char *s2= NULL;
|
||||
char *instance_name = NULL;
|
||||
|
||||
int rc = sscanf(fn, host_virtio_file_format_scan, &instance_name, &s1, &s2);
|
||||
if (rc != 2)
|
||||
{
|
||||
dlog3 ("'%s' does not satisfy scan pattern %s\n", fn, host_virtio_file_format_scan);
|
||||
if (s1)
|
||||
{
|
||||
free(s1);
|
||||
s1 = NULL;
|
||||
}
|
||||
|
||||
if (s2)
|
||||
{
|
||||
free(s2);
|
||||
s2 = NULL;
|
||||
}
|
||||
|
||||
if (instance_name)
|
||||
{
|
||||
free(instance_name);
|
||||
instance_name = NULL;
|
||||
}
|
||||
|
||||
rc = sscanf(fn, alt_host_virtio_file_format_scan, &instance_name, &s1, &s2);
|
||||
if (rc != 2)
|
||||
{
|
||||
dlog3 ("'%s' does not satisfy scan pattern %s\n", fn, alt_host_virtio_file_format_scan);
|
||||
if (instance_name)
|
||||
{
|
||||
free(instance_name);
|
||||
instance_name = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Valid instance filename found */
|
||||
name = instance_name ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Valid instance filename found */
|
||||
name = instance_name ;
|
||||
}
|
||||
|
||||
if (s1) free(s1);
|
||||
if (s2) free(s2);
|
||||
|
||||
if (instance_name)
|
||||
{
|
||||
free(instance_name);
|
||||
}
|
||||
|
||||
return (name);
|
||||
}
|
||||
|
||||
|
||||
bool virtio_check_filename ( char * fn )
|
||||
{
|
||||
string instance_name = virtio_instance_name ( fn ) ;
|
||||
if ( instance_name.size () == UUID_LEN )
|
||||
return true ;
|
||||
else
|
||||
return false ;
|
||||
}
|
||||
|
||||
/* Add the auto detected channel to the instance list
|
||||
* WARNING: This is where the cgcs.heartbeat.*.sock part is
|
||||
* removed from the channel and put into the instInfo
|
||||
* struct as a uuid value */
|
||||
int virtio_channel_add ( char * channel )
|
||||
{
|
||||
instInfo * instInfo_ptr ;
|
||||
int rc = FAIL_NOT_FOUND ;
|
||||
char * prefix1 = NULL ;
|
||||
char * prefix2 = NULL ;
|
||||
char * suffix = NULL ;
|
||||
char * uuid_ptr = NULL ;
|
||||
char * s1 = NULL ;
|
||||
string uuid = "";
|
||||
instInfo instance ;
|
||||
guestUtil_inst_init ( &instance );
|
||||
|
||||
rc = sscanf(channel, virtio_file_format_scan, &prefix1, &prefix2, &uuid_ptr, &suffix, &s1 );
|
||||
if ( rc != 4 )
|
||||
{
|
||||
elog ("failed to extract uuid from channel %s (num:%d)\n", channel, rc);
|
||||
rc = FAIL_INVALID_DATA ;
|
||||
goto virtio_channel_add_cleanup ;
|
||||
}
|
||||
|
||||
uuid = uuid_ptr ;
|
||||
if ( uuid.length() != UUID_LEN )
|
||||
{
|
||||
elog ("failed to get UUID from channel %s (uuid:%ld)\n", uuid.c_str(), uuid.length());
|
||||
rc = FAIL_INVALID_UUID ;
|
||||
goto virtio_channel_add_cleanup ;
|
||||
}
|
||||
|
||||
|
||||
instInfo_ptr = get_instInv_ptr()->get_inst ( uuid );
|
||||
if ( instInfo_ptr )
|
||||
{
|
||||
/* detected channel found */
|
||||
ilog ("%s add ; already provisioned\n", log_prefix(instInfo_ptr).c_str());
|
||||
rc = PASS ;
|
||||
}
|
||||
else if ( ( rc = get_instInv_ptr()->add_inst ( uuid, instance ) ) == PASS )
|
||||
{
|
||||
dlog ("%s add ; auto provisioned\n", instance.uuid.c_str());
|
||||
rc = PASS ;
|
||||
}
|
||||
else
|
||||
{
|
||||
elog ("%s add failed\n", uuid.c_str());
|
||||
rc = FAIL_INVALID_UUID ;
|
||||
}
|
||||
|
||||
if ( rc == PASS )
|
||||
{
|
||||
|
||||
/* get the recently added instance */
|
||||
instInfo_ptr = get_instInv_ptr()->get_inst ( uuid );
|
||||
if ( instInfo_ptr )
|
||||
{
|
||||
instInfo_ptr->uuid = uuid ;
|
||||
instInfo_ptr->chan = channel ;
|
||||
instInfo_ptr->fd_namespace = QEMU_CHANNEL_DIR ;
|
||||
instInfo_ptr->fd_namespace.append ("/") ;
|
||||
instInfo_ptr->fd_namespace.append (channel) ;
|
||||
|
||||
instInfo_ptr->connect_wait_in_secs = DEFAULT_CONNECT_WAIT ;
|
||||
|
||||
get_instInv_ptr()->reconnect_start ( (const char *)uuid_ptr ) ;
|
||||
}
|
||||
}
|
||||
|
||||
virtio_channel_add_cleanup:
|
||||
|
||||
if (prefix1) free(prefix1);
|
||||
if (prefix2) free(prefix2);
|
||||
if (suffix) free(suffix);
|
||||
if (uuid_ptr) free(uuid_ptr);
|
||||
if (s1) free (s1);
|
||||
|
||||
return(rc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Name : virtio_channel_connect
|
||||
*
|
||||
* Purpose : Connect to the channel specified by the instance pointer
|
||||
*
|
||||
*****************************************************************************/
|
||||
int virtio_channel_connect ( instInfo * instInfo_ptr )
|
||||
{
|
||||
int rc = PASS ;
|
||||
char buf[PATH_MAX];
|
||||
|
||||
if ( ! instInfo_ptr )
|
||||
{
|
||||
slog ("called with NULL instance pointer\n");
|
||||
return (FAIL_NULL_POINTER);
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s/cgcs.heartbeat.%s.sock", QEMU_CHANNEL_DIR, instInfo_ptr->uuid.data());
|
||||
|
||||
dlog ("... trying connect: %s\n", buf );
|
||||
|
||||
if (( instInfo_ptr->chan_fd > 0 ) && ( instInfo_ptr->chan_ok == true ))
|
||||
{
|
||||
if ( instInfo_ptr->connected )
|
||||
{
|
||||
ilog ("%s already connected\n", log_prefix(instInfo_ptr).c_str());
|
||||
return (PASS);
|
||||
}
|
||||
else
|
||||
{
|
||||
ilog ("%s socket and chan ok but not connected\n", log_prefix(instInfo_ptr).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
instInfo_ptr->chan_ok = false ;
|
||||
instInfo_ptr->connected = false ;
|
||||
|
||||
if ( instInfo_ptr->chan_fd )
|
||||
close (instInfo_ptr->chan_fd);
|
||||
|
||||
/* found channel */
|
||||
instInfo_ptr->chan_fd = socket ( AF_UNIX, CHAN_FLAGS, 0 );
|
||||
if ( instInfo_ptr->chan_fd <= 0 )
|
||||
{
|
||||
ilog("%s socket create failed for %s, (%d:%m)\n", log_prefix(instInfo_ptr).c_str(), buf, errno ) ;
|
||||
rc = FAIL_SOCKET_CREATE ;
|
||||
}
|
||||
else
|
||||
{
|
||||
int flags ;
|
||||
struct linger so_linger ;
|
||||
|
||||
/* get socket flags */
|
||||
flags = fcntl(instInfo_ptr->chan_fd, F_GETFL);
|
||||
if (flags < 0)
|
||||
{
|
||||
elog ("%s failed to get socket %d flags (%d:%m)\n",
|
||||
log_prefix(instInfo_ptr).c_str(),
|
||||
instInfo_ptr->chan_fd , errno);
|
||||
rc = FAIL_SOCKET_OPTION ;
|
||||
}
|
||||
|
||||
/* set socket as nonblocking */
|
||||
if ( flags & O_NONBLOCK )
|
||||
{
|
||||
dlog ("%s Socket already set as non-blocking\n",
|
||||
log_prefix(instInfo_ptr).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
flags = (flags | O_NONBLOCK);
|
||||
if (fcntl(instInfo_ptr->chan_fd, F_SETFL, flags) < 0)
|
||||
{
|
||||
elog ("%s failed to set socket %d nonblocking (%d:%m)\n",
|
||||
instInfo_ptr->uuid.data(),
|
||||
instInfo_ptr->chan_fd , errno);
|
||||
rc = FAIL_SOCKET_NOBLOCK ;
|
||||
}
|
||||
}
|
||||
so_linger.l_onoff = 1 ; /* true */
|
||||
so_linger.l_linger = 0 ; /* linger time is 0 ; no TIME_WAIT */
|
||||
|
||||
rc = setsockopt ( instInfo_ptr->chan_fd, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger));
|
||||
if ( rc )
|
||||
{
|
||||
elog ("%s failed to set linger=0 option (%d:%m)\n", log_prefix(instInfo_ptr).c_str(), errno );
|
||||
}
|
||||
}
|
||||
|
||||
if ( rc == PASS )
|
||||
{
|
||||
int len ;
|
||||
struct sockaddr_un un;
|
||||
un.sun_family = AF_UNIX;
|
||||
|
||||
strcpy(un.sun_path, buf);
|
||||
len = offsetof(struct sockaddr_un, sun_path) + strlen(buf);
|
||||
rc = connect(instInfo_ptr->chan_fd, (struct sockaddr *)&un, len);
|
||||
if (rc < 0)
|
||||
{
|
||||
elog ( "%s connect failed %s (%d:%d:%m)\n",
|
||||
log_prefix(instInfo_ptr).c_str(), buf, rc, errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
ilog ("%s connect accepted\n", log_prefix(instInfo_ptr).c_str() );
|
||||
instInfo_ptr->chan_ok = true ;
|
||||
instInfo_ptr->connected = true ;
|
||||
rc = PASS ;
|
||||
}
|
||||
}
|
||||
/* Handle errors */
|
||||
if ( rc != PASS )
|
||||
{
|
||||
/* TODO: cleanup */
|
||||
if (instInfo_ptr->chan_fd )
|
||||
{
|
||||
ilog ("%s closing socket %d\n",
|
||||
log_prefix(instInfo_ptr).c_str(),
|
||||
instInfo_ptr->chan_fd);
|
||||
|
||||
close (instInfo_ptr->chan_fd) ;
|
||||
instInfo_ptr->chan_fd = 0 ;
|
||||
instInfo_ptr->chan_ok = false ;
|
||||
instInfo_ptr->connected = false ;
|
||||
}
|
||||
/* TODO: consider removing this entry from the list */
|
||||
}
|
||||
return (rc);
|
||||
}
|
||||
|
||||
|
||||
int virtio_channel_connect ( string channel )
|
||||
{
|
||||
instInfo * instInfo_ptr = get_instInv_ptr()->get_inst ( channel ) ;
|
||||
if ( instInfo_ptr )
|
||||
{
|
||||
return ( virtio_channel_connect ( instInfo_ptr ));
|
||||
}
|
||||
elog ("%s instance lookup failed\n", channel.c_str() );
|
||||
return (FAIL_NULL_POINTER);
|
||||
}
|
24
mtce-guest/src/guestVirtio.h
Normal file
24
mtce-guest/src/guestVirtio.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef __GUESTVIRTIO_H__
|
||||
#define __GUESTVIRTIO_H__
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013-2015 Wind River Systems, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "guestBase.h"
|
||||
|
||||
bool virtio_check_filename ( char * fn );
|
||||
int virtio_channel_connect ( string channel );
|
||||
int virtio_channel_connect ( instInfo * inst_ptr );
|
||||
int virtio_channel_add ( char * chan_ptr );
|
||||
string virtio_instance_name ( char * fn );
|
||||
|
||||
#endif /* __GUESTVIRTIO_H__ */
|
28
mtce-guest/src/scripts/guest.ini
Normal file
28
mtce-guest/src/scripts/guest.ini
Normal file
@ -0,0 +1,28 @@
|
||||
; CGTS Guest Service daemons config file
|
||||
[agent] ; Agent Configuration
|
||||
rx_port = 2401 ; guestAgent inter-daemon messaging rx port number
|
||||
vim_cmd_port = 2410 ; vim to guestAgent command port
|
||||
hbs_failure_threshold = 1 ; Number of failures to accept before reporting the fault
|
||||
|
||||
[client] ; Client Configuration
|
||||
rx_port = 2411 ; guestAgent inter-daemon messaging rx port number
|
||||
hbs_failure_threshold = 1 ; Number of failures to accept before reporting the fault
|
||||
hbs_pulse_period = 400 ; Smallest allowable heartbeat interval in msecs
|
||||
|
||||
[timeouts] ; Configurable timeouts - values in seconds
|
||||
start_delay = 1 ; time in secs to wait before starting failure reporting
|
||||
|
||||
[debug] ;
|
||||
debug_timer = 0 ; enable(1) or disable(0) timer logs (tlog)
|
||||
debug_json = 0 ; enable(1) or disable(0) Json logs (jlog)
|
||||
debug_fsm = 0 ; enable(1) or disable(0) fsm logs (flog)
|
||||
debug_http = 0 ; enable(1) or disable(0) http logs (hlog)
|
||||
debug_alive = 0 ; enable(1) or disable(0) mtcAlive logs (alog)
|
||||
debug_msg = 0 ; enable(1) or disable(0) message logs (mlog)
|
||||
debug_state = 0 ; enable(1) or disable(0) state change logs (clog)
|
||||
debug_work = 0 ; enable(1) or disable(0) work queue trace logs (qlog)
|
||||
debug_level = 0 ; decimal mask 0..15 (8,4,2,1) and 16 for mem logging
|
||||
debug_all = 0 ; set all debug labels to the specified value
|
||||
|
||||
flush = 1 ; enable(1) or disable(0) force log flush (main loop)
|
||||
flush_thld = 5 ; if enabled - force flush after this number of loops
|
113
mtce-guest/src/scripts/guestAgent
Normal file
113
mtce-guest/src/scripts/guestAgent
Normal file
@ -0,0 +1,113 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# Copyright (c) 2013-2014, 2016 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
#
|
||||
# chkconfig: 2345 95 95
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: guestAgent
|
||||
# Default-Start: 3 5
|
||||
# Default-Stop: 0 1 2 6
|
||||
# Short-Description: Maintenance Client Daemon
|
||||
### END INIT INFO
|
||||
|
||||
. /etc/init.d/functions
|
||||
|
||||
DAEMON_NAME="guestAgent"
|
||||
DAEMON="/usr/local/bin/${DAEMON_NAME}"
|
||||
PIDFILE="/var/run/${DAEMON_NAME}.pid"
|
||||
PLATFORM_CONF="/etc/platform/platform.conf"
|
||||
|
||||
IFACE=""
|
||||
|
||||
# Linux Standard Base (LSB) Error Codes
|
||||
RETVAL=0
|
||||
GENERIC_ERROR=1
|
||||
INVALID_ARGS=2
|
||||
UNSUPPORTED_FEATURE=3
|
||||
NOT_INSTALLED=5
|
||||
NOT_RUNNING=7
|
||||
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin
|
||||
export PATH
|
||||
|
||||
if [ ! -e "${DAEMON}" ] ; then
|
||||
logger "${DAEMON} is missing"
|
||||
exit ${NOT_INSTALLED}
|
||||
fi
|
||||
|
||||
if [ -f ${PLATFORM_CONF} ] ; then
|
||||
IFACE=`cat ${PLATFORM_CONF} | grep management_interface | cut -f2 -d'='`
|
||||
if [ "${IFACE}" != "" ] ; then
|
||||
if ip link show $IFACE | grep -sq 'state DOWN'; then
|
||||
ip link set dev $IFACE up
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
logger "Starting ${DAEMON_NAME}"
|
||||
echo -n "Starting ${DAEMON_NAME}: "
|
||||
if [ -n "`pidof ${DAEMON_NAME}`" ] ; then
|
||||
echo -n "is already running "
|
||||
RETVAL=0
|
||||
else
|
||||
start-stop-daemon --start -b -x ${DAEMON} -- -l
|
||||
RETVAL=$?
|
||||
fi
|
||||
if [ ${RETVAL} -eq 0 ] ; then
|
||||
pid=`pidof ${DAEMON_NAME}`
|
||||
echo "OK"
|
||||
logger "${DAEMON} (${pid})"
|
||||
else
|
||||
echo "FAIL"
|
||||
RETVAL=${GENERIC_ERROR}
|
||||
fi
|
||||
;;
|
||||
|
||||
stop)
|
||||
logger "Stopping ${DAEMON_NAME}"
|
||||
echo -n "Stopping ${DAEMON_NAME}: "
|
||||
if [ -n "`pidof ${DAEMON_NAME}`" ] ; then
|
||||
killproc ${DAEMON_NAME}
|
||||
fi
|
||||
if [ -n "`pidof ${DAEMON_NAME}`" ] ; then
|
||||
echo "FAIL"
|
||||
RETVAL=${NOT_RUNNING}
|
||||
else
|
||||
echo "OK"
|
||||
fi
|
||||
rm -f ${PIDFILE}
|
||||
;;
|
||||
|
||||
restart)
|
||||
$0 stop
|
||||
$0 start
|
||||
;;
|
||||
|
||||
status)
|
||||
pid=`pidof ${DAEMON_NAME}`
|
||||
RETVAL=$?
|
||||
if [ ${RETVAL} -eq 0 ] ; then
|
||||
echo "${DAEMON_NAME} is running"
|
||||
else
|
||||
echo "${DAEMON_NAME} is NOT running"
|
||||
RETVAL=${NOT_RUNNING}
|
||||
fi
|
||||
;;
|
||||
|
||||
condrestart)
|
||||
$0 restart
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "usage: $0 { start | stop | status | restart | condrestart | status }"
|
||||
;;
|
||||
esac
|
||||
|
||||
exit ${RETVAL}
|
16
mtce-guest/src/scripts/guestAgent.logrotate
Normal file
16
mtce-guest/src/scripts/guestAgent.logrotate
Normal file
@ -0,0 +1,16 @@
|
||||
#daily
|
||||
|
||||
/var/log/guestAgent.log
|
||||
{
|
||||
nodateext
|
||||
size 10M
|
||||
rotate 5
|
||||
start 1
|
||||
missingok
|
||||
notifempty
|
||||
compress
|
||||
sharedscripts
|
||||
postrotate
|
||||
systemctl reload syslog-ng > /dev/null 2>&1 || true
|
||||
endscript
|
||||
}
|
442
mtce-guest/src/scripts/guestAgent.ocf
Normal file
442
mtce-guest/src/scripts/guestAgent.ocf
Normal file
@ -0,0 +1,442 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2013-2017 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
#
|
||||
# Support: www.windriver.com
|
||||
#
|
||||
# Purpose: This resource agent manages
|
||||
#
|
||||
# .... the Titanium Cloud Controller Maintenance Daemon
|
||||
#
|
||||
# RA Spec:
|
||||
#
|
||||
# http://www.opencf.org/cgi-bin/viewcvs.cgi/specs/ra/resource-agent-api.txt?rev=HEAD
|
||||
#
|
||||
#######################################################################
|
||||
# Initialization:
|
||||
|
||||
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
|
||||
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
|
||||
|
||||
|
||||
#######################################################################
|
||||
|
||||
# Fill in some defaults if no values are specified
|
||||
OCF_RESKEY_binary_default="guestAgent"
|
||||
OCF_RESKEY_config_default="/etc/mtc/guestAgent.ini"
|
||||
OCF_RESKEY_dbg_default="false"
|
||||
OCF_RESKEY_mode_default="normal"
|
||||
OCF_RESKEY_user_default="admin"
|
||||
OCF_RESKEY_pid_default="/var/run/guestAgent.pid"
|
||||
|
||||
|
||||
: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}}
|
||||
: ${OCF_RESKEY_config=${OCF_RESKEY_config_default}}
|
||||
: ${OCF_RESKEY_dbg=${OCF_RESKEY_dbg_default}}
|
||||
: ${OCF_RESKEY_mode=${OCF_RESKEY_mode_default}}
|
||||
: ${OCF_RESKEY_user=${OCF_RESKEY_user_default}}
|
||||
: ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}}
|
||||
|
||||
mydaemon="/usr/local/bin/${OCF_RESKEY_binary}"
|
||||
statusfile="/var/run/${OCF_RESKEY_binary}.info"
|
||||
|
||||
#######################################################################
|
||||
|
||||
usage() {
|
||||
cat <<UEND
|
||||
|
||||
usage: $0 (start|stop|reload|status|monitor|validate-all|meta-data)
|
||||
|
||||
$0 manages the Platform's Maintenance command and communication to compute server guest services.
|
||||
|
||||
The 'start' ..... operation starts the guestAgent service daemon.
|
||||
The 'stop' ...... operation stops the guestAgent service daemon.
|
||||
The 'reload' .... operation stops and then starts the guestAgent service daemon.
|
||||
The 'status' .... operation checks the status of the guestAgent service daemon.
|
||||
The 'monitor' ... operation indicates the in-service status of the guestAgent service daemon.
|
||||
The 'validate-all' operation reports whether the parameters are valid.
|
||||
The 'meta-data' . operation reports the guestAgent's meta-data information.
|
||||
|
||||
UEND
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
|
||||
meta_data() {
|
||||
if [ ${OCF_RESKEY_dbg} = "true" ] ; then
|
||||
ocf_log info "guestAgent:meta_data"
|
||||
fi
|
||||
|
||||
cat <<END
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
||||
<resource-agent name="guestAgent">
|
||||
<version>1.0</version>
|
||||
|
||||
<longdesc lang="en">
|
||||
This 'guestAgent' is an OCF Compliant Resource Agent that manages start, stop and in-
|
||||
service monitoring of Maintenance's guestAgent daemon on Wind River's Titanium Cloud.
|
||||
</longdesc>
|
||||
|
||||
<shortdesc lang="en">
|
||||
Manages the Titanium Cloud's Maintenance guestAgent service daemon.
|
||||
</shortdesc>
|
||||
|
||||
|
||||
<parameters>
|
||||
|
||||
<parameter name="mode" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
mode = normal ... run maintenance daemon in 'normal' mode (default)
|
||||
mode = passive ... run maintenance daemon in 'passive' mode
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Maintenance Mode Option</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_mode_default}"/>
|
||||
</parameter>
|
||||
|
||||
|
||||
<parameter name="dbg" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
dbg = false ... info, warn and err logs sent to output stream (default)
|
||||
dbg = true ... Additional dbg logs are also sent to the output stream
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Service Debug Control Option</shortdesc>
|
||||
<content type="boolean" default="${OCF_RESKEY_dbg_default}"/>
|
||||
</parameter>
|
||||
|
||||
</parameters>
|
||||
|
||||
|
||||
<actions>
|
||||
<action name="start" timeout="10s" />
|
||||
<action name="stop" timeout="10s" />
|
||||
<action name="monitor" timeout="10s" interval="300s" />
|
||||
<action name="meta-data" timeout="10s" />
|
||||
<action name="validate-all" timeout="10s" />
|
||||
</actions>
|
||||
</resource-agent>
|
||||
END
|
||||
return ${OCF_SUCCESS}
|
||||
}
|
||||
|
||||
guestAgent_validate() {
|
||||
|
||||
if [ ${OCF_RESKEY_dbg} = "true" ] ; then
|
||||
ocf_log info "guestAgent:validate"
|
||||
fi
|
||||
|
||||
check_binary "/usr/local/bin/${OCF_RESKEY_binary}"
|
||||
check_binary pidof
|
||||
|
||||
if [ ! -f ${OCF_RESKEY_config} ] ; then
|
||||
msg="${OCF_RESKEY_binary} file missing ${OCF_RESKEY_config}"
|
||||
ocf_log err "${msg}"
|
||||
return ${OCF_ERR_CONFIGURED}
|
||||
fi
|
||||
|
||||
return ${OCF_SUCCESS}
|
||||
}
|
||||
|
||||
guestAgent_status () {
|
||||
|
||||
proc="guestAgent:status"
|
||||
if [ ${OCF_RESKEY_dbg} = "true" ] ; then
|
||||
ocf_log info "guestAgent:status"
|
||||
fi
|
||||
|
||||
# remove the status file before we request a new
|
||||
rm -f ${statusfile}
|
||||
|
||||
# Verify the pid file exists as part of status
|
||||
for ((loop=0;loop<3;loop++)) {
|
||||
if [ -f ${OCF_RESKEY_pid} ] ; then
|
||||
break
|
||||
else
|
||||
sleep 1
|
||||
fi
|
||||
}
|
||||
|
||||
# See if the daemon is running
|
||||
pid=`cat ${OCF_RESKEY_pid}`
|
||||
kill -0 $pid 2> /dev/null
|
||||
if [ $? -eq 0 ] ; then
|
||||
|
||||
log_sig="${OCF_RESKEY_binary} In-Service Active Monitor Test"
|
||||
|
||||
# Ask the daemon to produce status
|
||||
ocf_run kill -s USR1 $pid
|
||||
|
||||
# Wait for the response
|
||||
for ((loop=0;loop<10;loop++)) {
|
||||
sleep 1
|
||||
if [ -f ${statusfile} ] ; then
|
||||
|
||||
ocf_log info "${log_sig} Passed ($loop)"
|
||||
return ${OCF_SUCCESS}
|
||||
|
||||
elif [ $loop -eq 5 ] ; then
|
||||
|
||||
# send the signal again
|
||||
ocf_run kill -s USR1 $pid
|
||||
|
||||
pid_stat=`cat /proc/${pid}/stat`
|
||||
ocf_log notice "${log_sig} is slow to respond"
|
||||
ocf_log notice "$pid_stat"
|
||||
|
||||
elif [ $loop -eq 8 ] ; then
|
||||
|
||||
pid_stat=`cat /proc/${pid}/stat`
|
||||
ocf_log warn "${log_sig} is very slow to respond"
|
||||
ocf_log warn "$pid_stat"
|
||||
|
||||
fi
|
||||
}
|
||||
log_procfs
|
||||
ocf_log err "${log_sig} Failed"
|
||||
return ${OCF_ERR_GENERIC}
|
||||
fi
|
||||
return ${OCF_NOT_RUNNING}
|
||||
}
|
||||
|
||||
guestAgent_monitor () {
|
||||
|
||||
proc="guestAgent:monitor"
|
||||
if [ ${OCF_RESKEY_dbg} = "true" ] ; then
|
||||
ocf_log info "${proc}"
|
||||
fi
|
||||
|
||||
# Uncomment if you want the monitor function to force-pass
|
||||
# return ${OCF_SUCCESS}
|
||||
|
||||
pid=`cat ${OCF_RESKEY_pid}`
|
||||
kill -0 $pid 2> /dev/null
|
||||
if [ $? -ne 0 ] ; then
|
||||
if [ ${OCF_RESKEY_dbg} = "true" ] ; then
|
||||
ocf_log info "${proc} called while ${OCF_RESKEY_binary} not running."
|
||||
fi
|
||||
return ${OCF_NOT_RUNNING}
|
||||
fi
|
||||
|
||||
guestAgent_status
|
||||
return $?
|
||||
}
|
||||
|
||||
|
||||
guestAgent_start () {
|
||||
|
||||
local rc
|
||||
|
||||
start_proc="guestAgent:start"
|
||||
if [ ${OCF_RESKEY_dbg} = "true" ] ; then
|
||||
ocf_log info "${start_proc}"
|
||||
fi
|
||||
|
||||
# Uncomment if you want the start function to force-pass without starting
|
||||
# return ${OCF_SUCCESS}
|
||||
|
||||
# If running then issue a ping test
|
||||
pid=`cat ${OCF_RESKEY_pid}`
|
||||
kill -0 $pid 2> /dev/null
|
||||
if [ $? -eq 0 ] ; then
|
||||
guestAgent_status
|
||||
rc=$?
|
||||
if [ $rc -ne ${OCF_SUCCESS} ] ; then
|
||||
msg="${start_proc} ping test failed rc=${rc}"
|
||||
ocf_log err "${msg}"
|
||||
guestAgent_stop
|
||||
else
|
||||
# Spec says to return success if process is already running for start
|
||||
pid=`cat ${OCF_RESKEY_pid}`
|
||||
kill -0 $pid 2> /dev/null
|
||||
if [ $? -eq 0 ] ; then
|
||||
ocf_log info "${start_proc} called while ${OCF_RESKEY_binary} is already running"
|
||||
return ${OCF_SUCCESS}
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# should not be running now or error
|
||||
pid=`cat ${OCF_RESKEY_pid}`
|
||||
kill -0 $pid 2> /dev/null
|
||||
if [ $? -eq 0 ] ; then
|
||||
msg="${start_proc} cannot kill off existing instance of ${OCF_RESKEY_binary}"
|
||||
ocf_log err "${msg}"
|
||||
return ${OCF_RUNNING_MASTER}
|
||||
fi
|
||||
|
||||
rm -f ${statusfile}
|
||||
|
||||
# default PID to null
|
||||
pid=""
|
||||
|
||||
# Try to Start the daemon
|
||||
${mydaemon}
|
||||
rc=$?
|
||||
|
||||
# verify it was started and set return code appropriately
|
||||
if [ $rc -eq ${OCF_SUCCESS} ] ; then
|
||||
# Verify the pid file exists as part of status
|
||||
for ((loop=0;loop<3;loop++)) {
|
||||
if [ -f ${OCF_RESKEY_pid} ] ; then
|
||||
break
|
||||
else
|
||||
ocf_log info "${start_proc} waiting ... loop=${loop}"
|
||||
sleep 1
|
||||
fi
|
||||
}
|
||||
|
||||
pid=`cat ${OCF_RESKEY_pid}`
|
||||
# ocf_log info "PID:$pid"
|
||||
kill -0 $pid 2> /dev/null
|
||||
if [ $? -ne 0 ] ; then
|
||||
rc=${OCF_FAILED_MASTER}
|
||||
else
|
||||
if [ ! -f ${statusfile} ] ; then
|
||||
ocf_log info "guestAgent: Startup Health Test Failed - missing info"
|
||||
rc = ${OCF_ERR_GENERIC}
|
||||
fi
|
||||
fi
|
||||
else
|
||||
ocf_log info "${start_proc} failed ${mydaemon} daemon rc=${rc}"
|
||||
rc = ${OCF_ERR_GENERIC}
|
||||
fi
|
||||
|
||||
# Record success or failure and return status
|
||||
if [ ${rc} -eq $OCF_SUCCESS ] ; then
|
||||
msg="${start_proc}ed pid=${pid}"
|
||||
ocf_log info "${msg}"
|
||||
else
|
||||
msg="${start_proc} failed rc=${rc}"
|
||||
ocf_log err "${msg}"
|
||||
rc=${OCF_NOT_RUNNING}
|
||||
fi
|
||||
return $rc
|
||||
}
|
||||
|
||||
guestAgent_confirm_stop () {
|
||||
|
||||
proc="guestAgent:confirm_stop"
|
||||
ocf_log info "${proc}"
|
||||
|
||||
pid=`pidof ${OCF_RESKEY_binary}`
|
||||
kill -0 ${pid} 2> /dev/null
|
||||
if [ $? -eq 0 ] ; then
|
||||
ocf_log info "${proc} 'kill -9 ${pid}'"
|
||||
kill -9 ${pid}
|
||||
ocf_log info "${proc}ed (by emergency kill -9 ${pid})"
|
||||
sleep 1
|
||||
fi
|
||||
rm -f ${OCF_RESKEY_pid}
|
||||
}
|
||||
|
||||
guestAgent_stop () {
|
||||
|
||||
proc="guestAgent:stop"
|
||||
|
||||
# See if the process is running by pidfile
|
||||
|
||||
pid=`pidof ${OCF_RESKEY_binary}`
|
||||
ocf_log info "${proc} PID:${pid}"
|
||||
kill -0 ${pid} 2> /dev/null
|
||||
if [ $? -ne 0 ] ; then
|
||||
ocf_log info "${proc} called while already stopped (no process)"
|
||||
guestAgent_confirm_stop
|
||||
return ${OCF_SUCCESS}
|
||||
fi
|
||||
|
||||
MAX=3
|
||||
for ((loop=0;loop<$MAX;loop++)) {
|
||||
|
||||
# verify stop with pidfile
|
||||
if [ -f ${OCF_RESKEY_pid} ] ; then
|
||||
|
||||
pid=`cat ${OCF_RESKEY_pid}`
|
||||
|
||||
# if pid file is gone we are done
|
||||
if [ ${pid} = "" ] ; then
|
||||
ocf_log info "${proc}ped (by -int)"
|
||||
break
|
||||
|
||||
# if pidfile is empty then kill by -int
|
||||
else
|
||||
|
||||
kill -0 ${pid} 2> /dev/null
|
||||
if [ $? -ne 0 ] ; then
|
||||
ocf_log info "${proc}ped (by pid)"
|
||||
break
|
||||
else
|
||||
ocf_log info "${proc}ping (by -int - loop:${loop})"
|
||||
kill -int ${pid}
|
||||
sleep 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
guestAgent_confirm_stop
|
||||
return ${OCF_SUCCESS}
|
||||
}
|
||||
|
||||
guestAgent_reload () {
|
||||
|
||||
local rc
|
||||
|
||||
proc="guestAgent:reload"
|
||||
if [ ${OCF_RESKEY_dbg} = "true" ] ; then
|
||||
ocf_log info "${proc}"
|
||||
fi
|
||||
|
||||
guestAgent_stop
|
||||
rc=$?
|
||||
if [ $rc -eq ${OCF_SUCCESS} ] ; then
|
||||
#sleep 1
|
||||
guestAgent_start
|
||||
rc=$?
|
||||
if [ $rc -eq ${OCF_SUCCESS} ] ; then
|
||||
msg="${proc}ed"
|
||||
ocf_log info "${mgs}"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ${rc} -ne ${OCF_SUCCESS} ] ; then
|
||||
msg="${OCF_RESKEY_binary}: failed to restart rc=${rc}"
|
||||
ocf_log info "${mgs}"
|
||||
fi
|
||||
|
||||
return ${rc}
|
||||
}
|
||||
|
||||
case ${__OCF_ACTION} in
|
||||
meta-data) meta_data
|
||||
exit ${OCF_SUCCESS}
|
||||
;;
|
||||
usage|help) usage
|
||||
exit ${OCF_SUCCESS}
|
||||
;;
|
||||
esac
|
||||
|
||||
ocf_log info "guestAgent:${__OCF_ACTION} action"
|
||||
|
||||
# Anything except meta-data and help must pass validation
|
||||
guestAgent_validate || exit $?
|
||||
|
||||
case ${__OCF_ACTION} in
|
||||
start) guestAgent_start
|
||||
;;
|
||||
stop) guestAgent_stop
|
||||
;;
|
||||
status) guestAgent_status
|
||||
;;
|
||||
reload) guestAgent_reload
|
||||
;;
|
||||
monitor) guestAgent_monitor
|
||||
;;
|
||||
validate-all) guestAgent_validate
|
||||
;;
|
||||
*) usage
|
||||
exit ${OCF_ERR_UNIMPLEMENTED}
|
||||
;;
|
||||
esac
|
16
mtce-guest/src/scripts/guestAgent.service
Normal file
16
mtce-guest/src/scripts/guestAgent.service
Normal file
@ -0,0 +1,16 @@
|
||||
[Unit]
|
||||
Description=Titanium Cloud Guest Agent
|
||||
After=network.target syslog.service
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
ExecStart=/etc/rc.d/init.d/guestAgent start
|
||||
ExecStop=/etc/rc.d/init.d/guestAgent stop
|
||||
ExecReload=/etc/rc.d/init.d/guestAgent reload
|
||||
PIDFile=/var/run/guestAgent.pid
|
||||
|
||||
Restart=no
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
160
mtce-guest/src/scripts/guestAgentTest.sh
Normal file
160
mtce-guest/src/scripts/guestAgentTest.sh
Normal file
@ -0,0 +1,160 @@
|
||||
#! /bin/bash
|
||||
|
||||
#
|
||||
# Copyright (c) 2015 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
echo "Running guestAgent guest services command testhead"
|
||||
|
||||
if [ -z $1 ] ; then
|
||||
echo "Error: must supply a host name as first arguement"
|
||||
echo "Syntax: $0 compute-1"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Args: $1 $2 $3"
|
||||
|
||||
banner="-----------------------------------------------------------"
|
||||
|
||||
hostname=$1
|
||||
hostuuid=`system host-show $hostname | grep uuid | cut -f 15 -d ' '`
|
||||
#hostuuid=`system host-show $hostname | grep uuid`
|
||||
|
||||
echo "hostname: $hostname"
|
||||
echo "hostuuid: $hostuuid"
|
||||
echo "Emulating VIM guest services commands against $hostname"
|
||||
|
||||
count=1
|
||||
|
||||
echo $banner
|
||||
echo "$count Create Host Services"
|
||||
echo $banner
|
||||
curl -i -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'User-Agent: vim/1.0' http://localhost:2410/v1/hosts/$hostuuid
|
||||
|
||||
count=$((count + 1))
|
||||
|
||||
echo $banner
|
||||
echo "$count Query Host Services"
|
||||
echo $banner
|
||||
curl -i -X GET -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'User-Agent: vim/1.0' http://localhost:2410/v1/hosts/$hostuuid
|
||||
|
||||
count=$((count + 1))
|
||||
|
||||
echo $banner
|
||||
echo "$count Enable Host Services"
|
||||
echo $banner
|
||||
curl -i -X PUT -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'User-Agent: vim/1.0' http://localhost:2410/v1/hosts/$hostuuid/enable -d '{"hostname": "compute-1", "uuid" : "010e7741-1173-4a3b-88fa-c4e5905500ca"}'
|
||||
|
||||
count=$((count + 1))
|
||||
|
||||
echo $banner
|
||||
echo "$count Create Guest Service: Instance 1"
|
||||
echo $banner
|
||||
curl -i -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'User-Agent: vim/1.0' http://localhost:2410/v1/instances/8d80875b-fa73-4ccb-bce3-1cd4df104400 -d '{"hostname": "compute-1", "uuid" : "8d80875b-fa73-4ccb-bce3-1cd4df104400", "channel" : "cgts-instance000001", "services" : ["heartbeat"]}'
|
||||
|
||||
count=$((count + 1))
|
||||
|
||||
echo $banner
|
||||
echo "$count Create Guest Service: Instance 2"
|
||||
echo $banner
|
||||
curl -i -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'User-Agent: vim/1.0' http://localhost:2410/v1/instances/8d80875b-fa73-4ccb-bce3-1cd4df104401 -d '{"hostname": "compute-1", "uuid" : "8d80875b-fa73-4ccb-bce3-1cd4df104401", "channel" : "cgts-instance000002", "services" : ["heartbeat"]}'
|
||||
|
||||
count=$((count + 1))
|
||||
|
||||
echo $banner
|
||||
echo "$count Query Guest Services: Instance 2:"
|
||||
echo $banner
|
||||
curl -i -X GET -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'User-Agent: vim/1.0' http://localhost:2410/v1/instances/8d80875b-fa73-4ccb-bce3-1cd4df104401
|
||||
|
||||
count=$((count + 1))
|
||||
|
||||
echo $banner
|
||||
echo "$count Query Guest Services: Instance 1:"
|
||||
echo $banner
|
||||
curl -i -X GET -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'User-Agent: vim/1.0' http://localhost:2410/v1/instances/8d80875b-fa73-4ccb-bce3-1cd4df104400
|
||||
|
||||
count=$((count + 1))
|
||||
|
||||
echo $banner
|
||||
echo "$count Enable Guest Service: Instance 2"
|
||||
echo $banner
|
||||
curl -i -X PATCH -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'User-Agent: vim/1.0' http://localhost:2410/v1/instances/8d80875b-fa73-4ccb-bce3-1cd4df104401 -d '{"hostname": "compute-1", "uuid" : "8d80875b-fa73-4ccb-bce3-1cd4df104401", "channel" : "cgts-instance000002", "services" : [{"service":"heartbeat" , "state":"enabled"}]}'
|
||||
|
||||
count=$((count + 1))
|
||||
|
||||
echo $banner
|
||||
echo "$count Query Guest Services: Instance 2:"
|
||||
echo $banner
|
||||
curl -i -X GET -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'User-Agent: vim/1.0' http://localhost:2410/v1/instances/8d80875b-fa73-4ccb-bce3-1cd4df104401
|
||||
|
||||
count=$((count + 1))
|
||||
|
||||
echo $banner
|
||||
echo "$count Disable Guest Service: Instance 2"
|
||||
echo $banner
|
||||
curl -i -X PATCH -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'User-Agent: vim/1.0' http://localhost:2410/v1/instances/8d80875b-fa73-4ccb-bce3-1cd4df104401 -d '{"hostname": "compute-1", "uuid" : "8d80875b-fa73-4ccb-bce3-1cd4df104401", "channel" : "cgts-instance000002", "services" : [{"service":"heartbeat" , "state":"disabled"}]}'
|
||||
|
||||
count=$((count + 1))
|
||||
|
||||
echo $banner
|
||||
echo "$count Query Guest Services: Instance 1:"
|
||||
echo $banner
|
||||
curl -i -X GET -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'User-Agent: vim/1.0' http://localhost:2410/v1/instances/8d80875b-fa73-4ccb-bce3-1cd4df104401
|
||||
|
||||
count=$((count + 1))
|
||||
|
||||
exit 0
|
||||
|
||||
echo $banner
|
||||
echo "$count Delete Guest Service: Instance 2"
|
||||
echo $banner
|
||||
curl -i -X DELETE -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'User-Agent: vim/1.0' http://localhost:2410/v1/instances/8d80875b-fa73-4ccb-bce3-1cd4df104401
|
||||
|
||||
count=$((count + 1))
|
||||
|
||||
echo $banner
|
||||
echo "$count Query Host Services"
|
||||
echo $banner
|
||||
curl -i -X GET -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'User-Agent: vim/1.0' http://localhost:2410/v1/hosts/$hostuuid
|
||||
|
||||
count=$((count + 1))
|
||||
|
||||
echo $banner
|
||||
echo "$count Disable Host Services"
|
||||
echo $banner
|
||||
curl -i -X PUT -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'User-Agent: vim/1.0' http://localhost:2410/v1/hosts/$hostuuid/disable -d '{"hostname": "compute-1", "uuid" : "010e7741-1173-4a3b-88fa-c4e5905500ca"}'
|
||||
|
||||
count=$((count + 1))
|
||||
|
||||
echo $banner
|
||||
echo "$count Delete Host Services"
|
||||
echo $banner
|
||||
curl -i -X DELETE -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'User-Agent: vim/1.0' http://localhost:2410/v1/hosts/$hostuuid
|
||||
|
||||
count=$((count + 1))
|
||||
|
||||
echo $banner
|
||||
echo "$count Enable Guest Service: Instance 1"
|
||||
echo $banner
|
||||
curl -i -X PATCH -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'User-Agent: vim/1.0' http://localhost:2410/v1/instances/8d80875b-fa73-4ccb-bce3-1cd4df104400 -d '{"hostname": "compute-1", "uuid" : "8d80875b-fa73-4ccb-bce3-1cd4df104400", "channel" : "cgts-instance000001", "services" : [{"service":"heartbeat" , "state":"enabled"}]}'
|
||||
|
||||
count=$((count + 1))
|
||||
|
||||
echo $banner
|
||||
echo "$count Disable Guest Service: Instance 1"
|
||||
echo $banner
|
||||
curl -i -X PATCH -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'User-Agent: vim/1.0' http://localhost:2410/v1/instances/8d80875b-fa73-4ccb-bce3-1cd4df104400 -d '{"hostname": "compute-1", "uuid" : "8d80875b-fa73-4ccb-bce3-1cd4df104400", "channel" : "cgts-instance000001", "services" : [{"service":"heartbeat" , "state":"disabled"}]}'
|
||||
|
||||
count=$((count + 1))
|
||||
|
||||
echo $banner
|
||||
echo "$count Enable Guest Service: Instance 1 - Change Channel"
|
||||
echo $banner
|
||||
curl -i -X PATCH -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'User-Agent: vim/1.0' http://localhost:2410/v1/instances/8d80875b-fa73-4ccb-bce3-1cd4df104400 -d '{"hostname": "compute-1", "uuid" : "8d80875b-fa73-4ccb-bce3-1cd4df104400", "channel" : "cgts-instance000003", "services" : [{"service":"heartbeat" , "state":"enabled"}]}'
|
||||
|
||||
echo $banner
|
||||
echo $banner
|
||||
|
||||
exit 0
|
113
mtce-guest/src/scripts/guestServer
Normal file
113
mtce-guest/src/scripts/guestServer
Normal file
@ -0,0 +1,113 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# Copyright (c) 2013-2014, 2016 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
#
|
||||
# chkconfig: 2345 95 95
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: guestServer
|
||||
# Default-Start: 3 5
|
||||
# Default-Stop: 0 1 2 6
|
||||
# Short-Description: Maintenance Client Daemon
|
||||
### END INIT INFO
|
||||
|
||||
. /etc/init.d/functions
|
||||
|
||||
DAEMON_NAME="guestServer"
|
||||
DAEMON="/usr/local/bin/${DAEMON_NAME}"
|
||||
PIDFILE="/var/run/${DAEMON_NAME}.pid"
|
||||
PLATFORM_CONF="/etc/platform/platform.conf"
|
||||
|
||||
IFACE=""
|
||||
|
||||
# Linux Standard Base (LSB) Error Codes
|
||||
RETVAL=0
|
||||
GENERIC_ERROR=1
|
||||
INVALID_ARGS=2
|
||||
UNSUPPORTED_FEATURE=3
|
||||
NOT_INSTALLED=5
|
||||
NOT_RUNNING=7
|
||||
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin
|
||||
export PATH
|
||||
|
||||
if [ ! -e "${DAEMON}" ] ; then
|
||||
logger "${DAEMON} is missing"
|
||||
exit ${NOT_INSTALLED}
|
||||
fi
|
||||
|
||||
if [ -f ${PLATFORM_CONF} ] ; then
|
||||
IFACE=`cat ${PLATFORM_CONF} | grep management_interface | cut -f2 -d'='`
|
||||
if [ "${IFACE}" != "" ] ; then
|
||||
if ip link show $IFACE | grep -sq 'state DOWN'; then
|
||||
ip link set dev $IFACE up
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
logger "Starting ${DAEMON_NAME}"
|
||||
echo -n "Starting ${DAEMON_NAME}: "
|
||||
if [ -n "`pidof ${DAEMON_NAME}`" ] ; then
|
||||
echo -n "is already running "
|
||||
RETVAL=0
|
||||
else
|
||||
start-stop-daemon --start -b -x ${DAEMON} -- -l
|
||||
RETVAL=$?
|
||||
fi
|
||||
if [ ${RETVAL} -eq 0 ] ; then
|
||||
pid=`pidof ${DAEMON_NAME}`
|
||||
echo "OK"
|
||||
logger "${DAEMON} (${pid})"
|
||||
else
|
||||
echo "FAIL"
|
||||
RETVAL=${GENERIC_ERROR}
|
||||
fi
|
||||
;;
|
||||
|
||||
stop)
|
||||
logger "Stopping ${DAEMON_NAME}"
|
||||
echo -n "Stopping ${DAEMON_NAME}: "
|
||||
if [ -n "`pidof ${DAEMON_NAME}`" ] ; then
|
||||
killproc ${DAEMON_NAME}
|
||||
fi
|
||||
if [ -n "`pidof ${DAEMON_NAME}`" ] ; then
|
||||
echo "FAIL"
|
||||
RETVAL=${NOT_RUNNING}
|
||||
else
|
||||
echo "OK"
|
||||
fi
|
||||
rm -f ${PIDFILE}
|
||||
;;
|
||||
|
||||
restart)
|
||||
$0 stop
|
||||
$0 start
|
||||
;;
|
||||
|
||||
status)
|
||||
pid=`pidof ${DAEMON_NAME}`
|
||||
RETVAL=$?
|
||||
if [ ${RETVAL} -eq 0 ] ; then
|
||||
echo "${DAEMON_NAME} is running"
|
||||
else
|
||||
echo "${DAEMON_NAME} is NOT running"
|
||||
RETVAL=${NOT_RUNNING}
|
||||
fi
|
||||
;;
|
||||
|
||||
condrestart)
|
||||
$0 restart
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "usage: $0 { start | stop | status | restart | condrestart | status }"
|
||||
;;
|
||||
esac
|
||||
|
||||
exit ${RETVAL}
|
17
mtce-guest/src/scripts/guestServer.logrotate
Normal file
17
mtce-guest/src/scripts/guestServer.logrotate
Normal file
@ -0,0 +1,17 @@
|
||||
#daily
|
||||
nodateext
|
||||
|
||||
/var/log/guestServer.log
|
||||
{
|
||||
nodateext
|
||||
size 10M
|
||||
rotate 5
|
||||
start 1
|
||||
missingok
|
||||
notifempty
|
||||
compress
|
||||
sharedscripts
|
||||
postrotate
|
||||
systemctl reload syslog-ng > /dev/null 2>&1 || true
|
||||
endscript
|
||||
}
|
25
mtce-guest/src/scripts/guestServer.pmon
Normal file
25
mtce-guest/src/scripts/guestServer.pmon
Normal file
@ -0,0 +1,25 @@
|
||||
[process]
|
||||
process = guestServer
|
||||
service = guestServer
|
||||
pidfile = /var/run/guestServer.pid
|
||||
script = /etc/init.d/guestServer
|
||||
style = lsb ; ocf or lsb
|
||||
severity = major ; minor, major, critical
|
||||
restarts = 3 ; restart retries before error assertion
|
||||
interval = 3 ; number of seconds to wait between restarts
|
||||
debounce = 10 ; number of seconds that a process needs to remain
|
||||
; running before degrade is removed and retry count
|
||||
; is cleared.
|
||||
startuptime = 1 ; Seconds to wait after process start before starting the debounce monitor
|
||||
mode = passive ; Monitoring mode: passive (default) or active
|
||||
; passive: process death monitoring (default: always)
|
||||
; active : heartbeat monitoring, i.e. request / response messaging
|
||||
; ignore : do not monitor or stop monitoring
|
||||
subfunction = compute ; Optional label.
|
||||
; Manage this process in the context of a combo host subfunction
|
||||
; Choices: compute or storage.
|
||||
; when specified pmond will wait for
|
||||
; /var/run/.compute_config_complete or
|
||||
; /var/run/.storage_config_complete
|
||||
; ... before managing this process with the specified subfunction
|
||||
; Excluding this label will cause this process to be managed by default on startup
|
23
mtce-guest/src/scripts/guestServer.service
Normal file
23
mtce-guest/src/scripts/guestServer.service
Normal file
@ -0,0 +1,23 @@
|
||||
[Unit]
|
||||
Description=Titanium Cloud Maintenance Guest Heartbeat Monitor Server
|
||||
After=network.target syslog.service config.service
|
||||
Before=pmon.service
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
ExecStart=/etc/rc.d/init.d/guestServer start
|
||||
ExecStop=/etc/rc.d/init.d/guestServer stop
|
||||
ExecReload=/etc/rc.d/init.d/guestServer reload
|
||||
PIDFile=/var/run/guestServer.pid
|
||||
|
||||
# Failure handling
|
||||
TimeoutStartSec=10s
|
||||
TimeoutStopSec=10s
|
||||
|
||||
# process recovery is handled by pmond
|
||||
Restart=no
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
Loading…
Reference in New Issue
Block a user