]> granicus.if.org Git - icinga2/blob - lib/methods/clrchecktask.cpp
Remove deprecated functions
[icinga2] / lib / methods / clrchecktask.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2016 Icinga Development Team (https://www.icinga.org/)  *
4  *                                                                            *
5  * This program is free software; you can redistribute it and/or              *
6  * modify it under the terms of the GNU General Public License                *
7  * as published by the Free Software Foundation; either version 2             *
8  * of the License, or (at your option) any later version.                     *
9  *                                                                            *
10  * This program is distributed in the hope that it will be useful,            *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
13  * GNU General Public License for more details.                               *
14  *                                                                            *
15  * You should have received a copy of the GNU General Public License          *
16  * along with this program; if not, write to the Free Software Foundation     *
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
18  ******************************************************************************/
19
20 #include "methods/clrchecktask.hpp"
21 #include "icinga/pluginutility.hpp"
22 #include "icinga/checkcommand.hpp"
23 #include "icinga/macroprocessor.hpp"
24 #include "icinga/icingaapplication.hpp"
25 #include "base/configtype.hpp"
26 #include "base/logger.hpp"
27 #include "base/function.hpp"
28 #include "base/utility.hpp"
29 #include "base/process.hpp"
30 #include <boost/algorithm/string/classification.hpp>
31 #include <boost/algorithm/string/split.hpp>
32 #include <boost/foreach.hpp>
33 #include <boost/thread/once.hpp>
34 #include <objbase.h>
35 #include <mscoree.h>
36
37 #import "mscorlib.tlb"
38 #pragma comment(lib, "mscoree.lib")
39
40 using namespace icinga;
41
42 REGISTER_SCRIPTFUNCTION_NS(Internal, ClrCheck,  &ClrCheckTask::ScriptFunc);
43
44 static boost::once_flag l_OnceFlag = BOOST_ONCE_INIT;
45
46 static boost::mutex l_ObjectsMutex;
47 static std::map<Checkable::Ptr, variant_t> l_Objects;
48
49 static mscorlib::_AppDomainPtr l_AppDomain;
50
51 static void InitializeClr(void)
52 {
53         ICorRuntimeHost *runtimeHost;
54
55         if (FAILED(CorBindToRuntimeEx(NULL, NULL,
56             STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN | STARTUP_CONCURRENT_GC,
57             CLSID_CorRuntimeHost, IID_ICorRuntimeHost, (void **)&runtimeHost))) {
58                 return;
59         }
60
61         runtimeHost->Start();
62
63         IUnknownPtr punkAppDomain = NULL;
64         runtimeHost->GetDefaultDomain(&punkAppDomain);
65
66         punkAppDomain->QueryInterface(__uuidof(mscorlib::_AppDomain), (void **)&l_AppDomain);
67
68         runtimeHost->Release();
69 }
70
71 static variant_t CreateClrType(const String& assemblyName, const String& typeName)
72 {
73         boost::call_once(l_OnceFlag, &InitializeClr);
74
75         try {
76                 mscorlib::_ObjectHandlePtr pObjectHandle;
77                 pObjectHandle = l_AppDomain->CreateInstanceFrom(assemblyName.CStr(), typeName.CStr());
78
79                 return pObjectHandle->Unwrap();
80         } catch (_com_error& error) {
81                 BOOST_THROW_EXCEPTION(std::runtime_error("Could not load .NET type: " + String(error.Description())));
82         }
83 }
84
85 static variant_t InvokeClrMethod(const variant_t& vtObject, const String& methodName, const Dictionary::Ptr& args)
86 {
87         CLSID clsid;
88         HRESULT hr = CLSIDFromProgID(L"System.Collections.Hashtable", &clsid);
89
90         mscorlib::IDictionaryPtr pHashtable;
91         CoCreateInstance(clsid, NULL, CLSCTX_ALL, __uuidof(mscorlib::IDictionary), (void **)&pHashtable);
92
93         ObjectLock olock(args);
94         BOOST_FOREACH(const Dictionary::Pair& kv, args) {
95                 String value = kv.second;
96                 pHashtable->Add(kv.first.CStr(), value.CStr());
97         }
98
99         mscorlib::_ObjectPtr pObject;
100         vtObject.pdispVal->QueryInterface(__uuidof(mscorlib::_Object), (void**)&pObject);
101         mscorlib::_TypePtr pType = pObject->GetType();
102
103         SAFEARRAY *psa = SafeArrayCreateVector(VT_VARIANT, 0, 1);
104
105         variant_t vtHashtable = static_cast<IUnknown *>(pHashtable);
106         LONG idx = 0;
107         SafeArrayPutElement(psa, &idx, &vtHashtable);
108
109         variant_t result = pType->InvokeMember_3(methodName.CStr(),
110                 mscorlib::BindingFlags_InvokeMethod,
111                 NULL,
112                 vtObject,
113                 psa);
114
115         SafeArrayDestroy(psa);
116
117         return result;
118 }
119
120 static void FillCheckResult(const CheckResult::Ptr& cr, variant_t vtResult)
121 {
122         mscorlib::_ObjectPtr pObject;
123         vtResult.pdispVal->QueryInterface(__uuidof(mscorlib::_Object), (void**)&pObject);
124         mscorlib::_TypePtr pType = pObject->GetType();
125
126         SAFEARRAY *psa = SafeArrayCreateVector(VT_VARIANT, 0, 0);
127         int lState = pType->InvokeMember_3("State",
128                 mscorlib::BindingFlags_GetField,
129                 NULL,
130                 vtResult,
131                 psa);
132         cr->SetState(static_cast<ServiceState>(lState));
133         bstr_t sOutput = pType->InvokeMember_3("Output",
134                 mscorlib::BindingFlags_GetField,
135                 NULL,
136                 vtResult,
137                 psa);
138         cr->SetOutput(static_cast<const char *>(sOutput));
139         bstr_t sPerformanceData = pType->InvokeMember_3("PerformanceData",
140                 mscorlib::BindingFlags_GetField,
141                 NULL,
142                 vtResult,
143                 psa);
144         SafeArrayDestroy(psa);
145         cr->SetPerformanceData(PluginUtility::SplitPerfdata(static_cast<const char *>(sPerformanceData)));
146 }
147
148 void ClrCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr,
149     const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros)
150 {
151         CheckCommand::Ptr commandObj = checkable->GetCheckCommand();
152         Value raw_command = commandObj->GetCommandLine();
153
154         Host::Ptr host;
155         Service::Ptr service;
156         tie(host, service) = GetHostService(checkable);
157
158         MacroProcessor::ResolverList resolvers;
159         if (service)
160                 resolvers.push_back(std::make_pair("service", service));
161         resolvers.push_back(std::make_pair("host", host));
162         resolvers.push_back(std::make_pair("command", commandObj));
163         resolvers.push_back(std::make_pair("icinga", IcingaApplication::GetInstance()));
164
165         Dictionary::Ptr envMacros = new Dictionary();
166
167         Dictionary::Ptr env = commandObj->GetEnv();
168
169         if (env) {
170                 ObjectLock olock(env);
171                 BOOST_FOREACH(const Dictionary::Pair& kv, env) {
172                         String name = kv.second;
173
174                         Value value = MacroProcessor::ResolveMacros(name, resolvers, checkable->GetLastCheckResult(),
175                             NULL, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
176
177                         envMacros->Set(kv.first, value);
178                 }
179         }
180
181         variant_t vtObject;
182
183         {
184                 boost::mutex::scoped_lock lock(l_ObjectsMutex);
185
186                 std::map<Checkable::Ptr, variant_t>::iterator it = l_Objects.find(checkable);
187
188                 if (it != l_Objects.end()) {
189                         vtObject = it->second;
190                 } else {
191                         String clr_assembly = MacroProcessor::ResolveMacros("$clr_assembly$", resolvers, checkable->GetLastCheckResult(),
192                             NULL, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
193                         String clr_type = MacroProcessor::ResolveMacros("$clr_type$", resolvers, checkable->GetLastCheckResult(),
194                             NULL, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
195
196                         if (resolvedMacros && !useResolvedMacros)
197                                 return;
198
199                         vtObject = CreateClrType(clr_assembly, clr_type);
200                         l_Objects[checkable] = vtObject;
201                 }
202         }
203
204         try {
205                 variant_t vtResult = InvokeClrMethod(vtObject, "Check", envMacros);
206                 FillCheckResult(cr, vtResult);
207                 checkable->ProcessCheckResult(cr);
208         } catch (_com_error& error) {
209                 cr->SetOutput("Failed to invoke .NET method: " + String(error.Description()));
210                 cr->SetState(ServiceUnknown);
211                 checkable->ProcessCheckResult(cr);
212         }
213 }