diff options
| author | Sean Hall <r.sean.hall@gmail.com> | 2018-12-16 21:19:24 -0600 |
|---|---|---|
| committer | Sean Hall <r.sean.hall@gmail.com> | 2018-12-16 21:20:40 -0600 |
| commit | 95a5a8f9efef02ddcec5b3f69be99a00d71a802a (patch) | |
| tree | f0a92b8e8e37e17af6053db11f1b8a7a532cd12c /src/ca/scaapppool.cpp | |
| parent | aec6e9a4b21accd2e8aeb2cb36ad1cdc8f308f79 (diff) | |
| download | wix-95a5a8f9efef02ddcec5b3f69be99a00d71a802a.tar.gz wix-95a5a8f9efef02ddcec5b3f69be99a00d71a802a.tar.bz2 wix-95a5a8f9efef02ddcec5b3f69be99a00d71a802a.zip | |
Import implementation of IisCA from old repo's scasched/scaexec.
Diffstat (limited to 'src/ca/scaapppool.cpp')
| -rw-r--r-- | src/ca/scaapppool.cpp | 594 |
1 files changed, 594 insertions, 0 deletions
diff --git a/src/ca/scaapppool.cpp b/src/ca/scaapppool.cpp new file mode 100644 index 00000000..781c55ca --- /dev/null +++ b/src/ca/scaapppool.cpp | |||
| @@ -0,0 +1,594 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | #include "precomp.h" | ||
| 4 | |||
| 5 | /*------------------------------------------------------------------ | ||
| 6 | AppPool table: | ||
| 7 | |||
| 8 | Column Type Nullable Example Value | ||
| 9 | AppPool s72 No TestPool | ||
| 10 | Name s72 No "TestPool" | ||
| 11 | Component_ s72 No ComponentName | ||
| 12 | Attributes i2 No 8 (APATTR_OTHERUSER) | ||
| 13 | User_ s72 Yes UserKey | ||
| 14 | RecycleMinutes i2 Yes 500 | ||
| 15 | RecycleRequests i2 Yes 5000 | ||
| 16 | RecycleTimes s72 Yes "1:45,13:30,22:00" | ||
| 17 | IdleTimeout i2 Yes 15 | ||
| 18 | QueueLimit i2 Yes 500 | ||
| 19 | CPUMon s72 Yes "65,500,1" (65% CPU usage, 500 minutes, Shutdown Action) | ||
| 20 | MaxProc i2 Yes 5 | ||
| 21 | ManagedRuntimeVersion s72 Yes "v2.0" | ||
| 22 | ManagedPipelineMode s72 Yes "Integrated" | ||
| 23 | |||
| 24 | Notes: | ||
| 25 | RecycleTimes is a comma delimeted list of times. CPUMon is a | ||
| 26 | comma delimeted list of the following format: | ||
| 27 | <percent CPU usage>,<refress minutes>,<Action>. The values for | ||
| 28 | Action are 1 (Shutdown) and 0 (No Action). | ||
| 29 | |||
| 30 | ------------------------------------------------------------------*/ | ||
| 31 | |||
| 32 | enum eAppPoolQuery { apqAppPool = 1, apqName, apqComponent, apqAttributes, apqUser, apqRecycleMinutes, apqRecycleRequests, apqRecycleTimes, apqVirtualMemory, apqPrivateMemory, apqIdleTimeout, apqQueueLimit, apqCpuMon, apqMaxProc, apqManagedRuntimeVersion, apqManagedPipelineMode, apqInstalled, apqAction }; | ||
| 33 | |||
| 34 | enum eComponentAttrQuery { caqComponent = 1, caqAttributes }; | ||
| 35 | |||
| 36 | // prototypes | ||
| 37 | static HRESULT AppPoolExists( | ||
| 38 | __in IMSAdminBase* piMetabase, | ||
| 39 | __in LPCWSTR wzAppPool | ||
| 40 | ); | ||
| 41 | |||
| 42 | // functions | ||
| 43 | |||
| 44 | void ScaAppPoolFreeList( | ||
| 45 | __in SCA_APPPOOL* psapList | ||
| 46 | ) | ||
| 47 | { | ||
| 48 | SCA_APPPOOL* psapDelete = psapList; | ||
| 49 | while (psapList) | ||
| 50 | { | ||
| 51 | psapDelete = psapList; | ||
| 52 | psapList = psapList->psapNext; | ||
| 53 | |||
| 54 | MemFree(psapDelete); | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | |||
| 59 | HRESULT ScaAppPoolRead( | ||
| 60 | __inout SCA_APPPOOL** ppsapList, | ||
| 61 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | ||
| 62 | __inout LPWSTR *ppwzCustomActionData | ||
| 63 | ) | ||
| 64 | { | ||
| 65 | Assert(ppsapList); | ||
| 66 | |||
| 67 | HRESULT hr = S_OK; | ||
| 68 | |||
| 69 | MSIHANDLE hRec, hRecComp; | ||
| 70 | LPWSTR pwzData = NULL; | ||
| 71 | SCA_APPPOOL* psap = NULL; | ||
| 72 | WCA_WRAPQUERY_HANDLE hAppPoolQuery = NULL; | ||
| 73 | WCA_WRAPQUERY_HANDLE hComponentQuery = NULL; | ||
| 74 | |||
| 75 | hr = WcaBeginUnwrapQuery(&hAppPoolQuery, ppwzCustomActionData); | ||
| 76 | ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead"); | ||
| 77 | |||
| 78 | if (0 == WcaGetQueryRecords(hAppPoolQuery)) | ||
| 79 | { | ||
| 80 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaAppPoolRead() - required table not present"); | ||
| 81 | ExitFunction1(hr = S_FALSE); | ||
| 82 | } | ||
| 83 | |||
| 84 | hr = WcaBeginUnwrapQuery(&hComponentQuery, ppwzCustomActionData); | ||
| 85 | ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead"); | ||
| 86 | |||
| 87 | // loop through all the AppPools | ||
| 88 | while (S_OK == (hr = WcaFetchWrappedRecord(hAppPoolQuery, &hRec))) | ||
| 89 | { | ||
| 90 | // Add this record's information into the list of things to process. | ||
| 91 | hr = AddAppPoolToList(ppsapList); | ||
| 92 | ExitOnFailure(hr, "failed to add app pool to app pool list"); | ||
| 93 | |||
| 94 | psap = *ppsapList; | ||
| 95 | |||
| 96 | hr = WcaGetRecordString(hRec, apqComponent, &pwzData); | ||
| 97 | ExitOnFailure(hr, "failed to get AppPool.Component"); | ||
| 98 | |||
| 99 | if (pwzData && *pwzData) | ||
| 100 | { | ||
| 101 | psap->fHasComponent = TRUE; | ||
| 102 | |||
| 103 | hr = ::StringCchCopyW(psap->wzComponent, countof(psap->wzComponent), pwzData); | ||
| 104 | ExitOnFailure(hr, "failed to copy component name: %ls", pwzData); | ||
| 105 | |||
| 106 | hr = WcaGetRecordInteger(hRec, apqInstalled, (int *)&psap->isInstalled); | ||
| 107 | ExitOnFailure(hr, "Failed to get Component installed state for app pool"); | ||
| 108 | |||
| 109 | hr = WcaGetRecordInteger(hRec, apqAction, (int *)&psap->isAction); | ||
| 110 | ExitOnFailure(hr, "Failed to get Component action state for app pool"); | ||
| 111 | |||
| 112 | WcaFetchWrappedReset(hComponentQuery); | ||
| 113 | hr = WcaFetchWrappedRecordWhereString(hComponentQuery, caqComponent, psap->wzComponent, &hRecComp); | ||
| 114 | ExitOnFailure(hr, "Failed to fetch Component.Attributes for Component '%ls'", psap->wzComponent); | ||
| 115 | |||
| 116 | hr = WcaGetRecordInteger(hRecComp, caqAttributes, &psap->iCompAttributes); | ||
| 117 | ExitOnFailure(hr, "failed to get Component.Attributes"); | ||
| 118 | } | ||
| 119 | |||
| 120 | hr = WcaGetRecordString(hRec, apqAppPool, &pwzData); | ||
| 121 | ExitOnFailure(hr, "failed to get AppPool.AppPool"); | ||
| 122 | hr = ::StringCchCopyW(psap->wzAppPool, countof(psap->wzAppPool), pwzData); | ||
| 123 | ExitOnFailure(hr, "failed to copy AppPool name: %ls", pwzData); | ||
| 124 | |||
| 125 | hr = WcaGetRecordString(hRec, apqName, &pwzData); | ||
| 126 | ExitOnFailure(hr, "failed to get AppPool.Name"); | ||
| 127 | hr = ::StringCchCopyW(psap->wzName, countof(psap->wzName), pwzData); | ||
| 128 | ExitOnFailure(hr, "failed to copy app pool name: %ls", pwzData); | ||
| 129 | hr = ::StringCchPrintfW(psap->wzKey, countof(psap->wzKey), L"/LM/W3SVC/AppPools/%s", pwzData); | ||
| 130 | ExitOnFailure(hr, "failed to format app pool key name"); | ||
| 131 | |||
| 132 | hr = WcaGetRecordInteger(hRec, apqAttributes, &psap->iAttributes); | ||
| 133 | ExitOnFailure(hr, "failed to get AppPool.Attributes"); | ||
| 134 | |||
| 135 | hr = WcaGetRecordString(hRec, apqUser, &pwzData); | ||
| 136 | ExitOnFailure(hr, "failed to get AppPool.User"); | ||
| 137 | hr = ScaGetUserDeferred(pwzData, hUserQuery, &psap->suUser); | ||
| 138 | ExitOnFailure(hr, "failed to get user: %ls", pwzData); | ||
| 139 | |||
| 140 | hr = WcaGetRecordInteger(hRec, apqRecycleRequests, &psap->iRecycleRequests); | ||
| 141 | ExitOnFailure(hr, "failed to get AppPool.RecycleRequests"); | ||
| 142 | |||
| 143 | hr = WcaGetRecordInteger(hRec, apqRecycleMinutes, &psap->iRecycleMinutes); | ||
| 144 | ExitOnFailure(hr, "failed to get AppPool.Minutes"); | ||
| 145 | |||
| 146 | hr = WcaGetRecordString(hRec, apqRecycleTimes, &pwzData); | ||
| 147 | ExitOnFailure(hr, "failed to get AppPool.RecycleTimes"); | ||
| 148 | hr = ::StringCchCopyW(psap->wzRecycleTimes, countof(psap->wzRecycleTimes), pwzData); | ||
| 149 | ExitOnFailure(hr, "failed to copy recycle value: %ls", pwzData); | ||
| 150 | |||
| 151 | hr = WcaGetRecordInteger(hRec, apqVirtualMemory, &psap->iVirtualMemory); | ||
| 152 | ExitOnFailure(hr, "failed to get AppPool.VirtualMemory"); | ||
| 153 | |||
| 154 | hr = WcaGetRecordInteger(hRec, apqPrivateMemory, &psap->iPrivateMemory); | ||
| 155 | ExitOnFailure(hr, "failed to get AppPool.PrivateMemory"); | ||
| 156 | |||
| 157 | hr = WcaGetRecordInteger(hRec, apqIdleTimeout, &psap->iIdleTimeout); | ||
| 158 | ExitOnFailure(hr, "failed to get AppPool.IdleTimeout"); | ||
| 159 | |||
| 160 | hr = WcaGetRecordInteger(hRec, apqQueueLimit, &psap->iQueueLimit); | ||
| 161 | ExitOnFailure(hr, "failed to get AppPool.QueueLimit"); | ||
| 162 | |||
| 163 | hr = WcaGetRecordString(hRec, apqCpuMon, &pwzData); | ||
| 164 | ExitOnFailure(hr, "failed to get AppPool.CPUMon"); | ||
| 165 | hr = ::StringCchCopyW(psap->wzCpuMon, countof(psap->wzCpuMon), pwzData); | ||
| 166 | ExitOnFailure(hr, "failed to copy cpu monitor value: %ls", pwzData); | ||
| 167 | |||
| 168 | hr = WcaGetRecordInteger(hRec, apqMaxProc, &psap->iMaxProcesses); | ||
| 169 | ExitOnFailure(hr, "failed to get AppPool.MaxProc"); | ||
| 170 | |||
| 171 | hr = WcaGetRecordString(hRec, apqManagedRuntimeVersion, &pwzData); | ||
| 172 | ExitOnFailure(hr, "failed to get AppPool.ManagedRuntimeVersion"); | ||
| 173 | hr = ::StringCchCopyW(psap->wzManagedRuntimeVersion, countof(psap->wzManagedRuntimeVersion), pwzData); | ||
| 174 | ExitOnFailure(hr, "failed to copy ManagedRuntimeVersion value: %ls", pwzData); | ||
| 175 | |||
| 176 | hr = WcaGetRecordString(hRec, apqManagedPipelineMode, &pwzData); | ||
| 177 | ExitOnFailure(hr, "failed to get AppPool.ManagedPipelineMode"); | ||
| 178 | hr = ::StringCchCopyW(psap->wzManagedPipelineMode, countof(psap->wzManagedPipelineMode), pwzData); | ||
| 179 | ExitOnFailure(hr, "failed to copy ManagedPipelineMode value: %ls", pwzData); | ||
| 180 | |||
| 181 | } | ||
| 182 | |||
| 183 | if (E_NOMOREITEMS == hr) | ||
| 184 | { | ||
| 185 | hr = S_OK; | ||
| 186 | } | ||
| 187 | ExitOnFailure(hr, "failure while processing AppPools"); | ||
| 188 | |||
| 189 | LExit: | ||
| 190 | WcaFinishUnwrapQuery(hAppPoolQuery); | ||
| 191 | WcaFinishUnwrapQuery(hComponentQuery); | ||
| 192 | |||
| 193 | ReleaseStr(pwzData); | ||
| 194 | return hr; | ||
| 195 | } | ||
| 196 | |||
| 197 | |||
| 198 | HRESULT ScaFindAppPool( | ||
| 199 | __in IMSAdminBase* piMetabase, | ||
| 200 | __in LPCWSTR wzAppPool, | ||
| 201 | __out_ecount(cchName) LPWSTR wzName, | ||
| 202 | __in DWORD cchName, | ||
| 203 | __in SCA_APPPOOL *psapList | ||
| 204 | ) | ||
| 205 | { | ||
| 206 | Assert(piMetabase && wzAppPool && *wzAppPool && wzName && *wzName); | ||
| 207 | |||
| 208 | HRESULT hr = S_OK; | ||
| 209 | |||
| 210 | // check memory first | ||
| 211 | SCA_APPPOOL* psap = psapList; | ||
| 212 | for (; psap; psap = psap->psapNext) | ||
| 213 | { | ||
| 214 | if (0 == lstrcmpW(psap->wzAppPool, wzAppPool)) | ||
| 215 | { | ||
| 216 | break; | ||
| 217 | } | ||
| 218 | } | ||
| 219 | ExitOnNull(psap, hr, HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Could not find the app pool: %ls", wzAppPool); | ||
| 220 | |||
| 221 | // copy the web app pool name | ||
| 222 | hr = ::StringCchCopyW(wzName, cchName, psap->wzName); | ||
| 223 | ExitOnFailure(hr, "failed to copy app pool name while finding app pool: %ls", psap->wzName); | ||
| 224 | |||
| 225 | // if it's not being installed now, check if it exists already | ||
| 226 | if (!psap->fHasComponent) | ||
| 227 | { | ||
| 228 | hr = AppPoolExists(piMetabase, psap->wzName); | ||
| 229 | ExitOnFailure(hr, "failed to check for existence of app pool: %ls", psap->wzName); | ||
| 230 | } | ||
| 231 | |||
| 232 | LExit: | ||
| 233 | return hr; | ||
| 234 | } | ||
| 235 | |||
| 236 | |||
| 237 | static HRESULT AppPoolExists( | ||
| 238 | __in IMSAdminBase* piMetabase, | ||
| 239 | __in LPCWSTR wzAppPool | ||
| 240 | ) | ||
| 241 | { | ||
| 242 | Assert(piMetabase && wzAppPool && *wzAppPool); | ||
| 243 | |||
| 244 | HRESULT hr = S_OK; | ||
| 245 | WCHAR wzSubKey[METADATA_MAX_NAME_LEN]; | ||
| 246 | |||
| 247 | for (DWORD dwIndex = 0; SUCCEEDED(hr); ++dwIndex) | ||
| 248 | { | ||
| 249 | hr = piMetabase->EnumKeys(METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC/AppPools", wzSubKey, dwIndex); | ||
| 250 | if (SUCCEEDED(hr) && 0 == lstrcmpW(wzSubKey, wzAppPool)) | ||
| 251 | { | ||
| 252 | hr = S_OK; | ||
| 253 | break; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | if (E_NOMOREITEMS == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) | ||
| 258 | { | ||
| 259 | hr = S_FALSE; | ||
| 260 | } | ||
| 261 | |||
| 262 | return hr; | ||
| 263 | } | ||
| 264 | |||
| 265 | |||
| 266 | HRESULT ScaAppPoolInstall( | ||
| 267 | __in IMSAdminBase* piMetabase, | ||
| 268 | __in SCA_APPPOOL* psapList | ||
| 269 | ) | ||
| 270 | { | ||
| 271 | Assert(piMetabase); | ||
| 272 | |||
| 273 | HRESULT hr = S_OK; | ||
| 274 | |||
| 275 | for (SCA_APPPOOL* psap = psapList; psap; psap = psap->psapNext) | ||
| 276 | { | ||
| 277 | // if we are installing the app pool | ||
| 278 | if (psap->fHasComponent && WcaIsInstalling(psap->isInstalled, psap->isAction)) | ||
| 279 | { | ||
| 280 | hr = ScaWriteAppPool(piMetabase, psap); | ||
| 281 | ExitOnFailure(hr, "failed to write AppPool '%ls' to metabase", psap->wzAppPool); | ||
| 282 | } | ||
| 283 | } | ||
| 284 | |||
| 285 | LExit: | ||
| 286 | return hr; | ||
| 287 | } | ||
| 288 | |||
| 289 | |||
| 290 | HRESULT ScaAppPoolUninstall( | ||
| 291 | __in IMSAdminBase* piMetabase, | ||
| 292 | __in SCA_APPPOOL* psapList | ||
| 293 | ) | ||
| 294 | { | ||
| 295 | Assert(piMetabase); | ||
| 296 | |||
| 297 | HRESULT hr = S_OK; | ||
| 298 | |||
| 299 | for (SCA_APPPOOL* psap = psapList; psap; psap = psap->psapNext) | ||
| 300 | { | ||
| 301 | // if we are uninstalling the app pool | ||
| 302 | if (psap->fHasComponent && WcaIsUninstalling(psap->isInstalled, psap->isAction)) | ||
| 303 | { | ||
| 304 | hr = ScaRemoveAppPool(piMetabase, psap); | ||
| 305 | ExitOnFailure(hr, "Failed to remove AppPool '%ls' from metabase", psap->wzAppPool); | ||
| 306 | } | ||
| 307 | } | ||
| 308 | |||
| 309 | LExit: | ||
| 310 | return hr; | ||
| 311 | } | ||
| 312 | |||
| 313 | |||
| 314 | HRESULT ScaWriteAppPool( | ||
| 315 | __in IMSAdminBase* piMetabase, | ||
| 316 | __in SCA_APPPOOL* psap | ||
| 317 | ) | ||
| 318 | { | ||
| 319 | Assert(piMetabase && psap); | ||
| 320 | |||
| 321 | HRESULT hr = S_OK; | ||
| 322 | DWORD dwIdentity = 0xFFFFFFFF; | ||
| 323 | BOOL fExists = FALSE; | ||
| 324 | LPWSTR pwzValue = NULL; | ||
| 325 | LPWSTR wz = NULL; | ||
| 326 | |||
| 327 | hr = AppPoolExists(piMetabase, psap->wzName); | ||
| 328 | ExitOnFailure(hr, "failed to check if app pool already exists"); | ||
| 329 | if (S_FALSE == hr) | ||
| 330 | { | ||
| 331 | // didn't find the AppPool key, so we need to create it | ||
| 332 | hr = ScaCreateMetabaseKey(piMetabase, psap->wzKey, L""); | ||
| 333 | ExitOnFailure(hr, "failed to create AppPool key: %ls", psap->wzKey); | ||
| 334 | |||
| 335 | // mark it as an AppPool | ||
| 336 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsApplicationPool"); | ||
| 337 | ExitOnFailure(hr, "failed to mark key as AppPool key: %ls", psap->wzKey); | ||
| 338 | |||
| 339 | // TODO: Make this an Attribute? | ||
| 340 | // set autostart value | ||
| 341 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_AUTO_START, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)1); | ||
| 342 | ExitOnFailure(hr, "failed to mark key as AppPool key: %ls", psap->wzKey); | ||
| 343 | } | ||
| 344 | else | ||
| 345 | { | ||
| 346 | fExists = TRUE; | ||
| 347 | } | ||
| 348 | |||
| 349 | // | ||
| 350 | // Set the AppPool Recycling Tab | ||
| 351 | // | ||
| 352 | if (MSI_NULL_INTEGER != psap->iRecycleMinutes) | ||
| 353 | { | ||
| 354 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_TIME, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iRecycleMinutes)); | ||
| 355 | ExitOnFailure(hr, "failed to set periodic restart time"); | ||
| 356 | } | ||
| 357 | |||
| 358 | if (MSI_NULL_INTEGER != psap->iRecycleRequests) | ||
| 359 | { | ||
| 360 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_REQUEST_COUNT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iRecycleRequests)); | ||
| 361 | ExitOnFailure(hr, "failed to set periodic restart request count"); | ||
| 362 | } | ||
| 363 | |||
| 364 | if (*psap->wzRecycleTimes) | ||
| 365 | { | ||
| 366 | // Add another NULL' onto pwz since it's a 'MULTISZ' | ||
| 367 | hr = StrAllocString(&pwzValue, psap->wzRecycleTimes, 0); | ||
| 368 | ExitOnFailure(hr, "failed to allocate string for MULTISZ"); | ||
| 369 | hr = StrAllocConcat(&pwzValue, L"\0", 1); | ||
| 370 | ExitOnFailure(hr, "failed to add second null to RecycleTime multisz"); | ||
| 371 | |||
| 372 | // Replace the commas with NULLs | ||
| 373 | wz = pwzValue; | ||
| 374 | while (NULL != (wz = wcschr(wz, L','))) | ||
| 375 | { | ||
| 376 | *wz = L'\0'; | ||
| 377 | ++wz; | ||
| 378 | } | ||
| 379 | |||
| 380 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_SCHEDULE, METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, (LPVOID)pwzValue); | ||
| 381 | ExitOnFailure(hr, "failed to set periodic restart schedule"); | ||
| 382 | } | ||
| 383 | |||
| 384 | if (MSI_NULL_INTEGER != psap->iVirtualMemory) | ||
| 385 | { | ||
| 386 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_MEMORY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iVirtualMemory)); | ||
| 387 | ExitOnFailure(hr, "failed to set periodic restart memory count"); | ||
| 388 | } | ||
| 389 | |||
| 390 | if (MSI_NULL_INTEGER != psap->iPrivateMemory) | ||
| 391 | { | ||
| 392 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_PRIVATE_MEMORY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iPrivateMemory)); | ||
| 393 | ExitOnFailure(hr, "failed to set periodic restart private memory count"); | ||
| 394 | } | ||
| 395 | |||
| 396 | |||
| 397 | // | ||
| 398 | // Set AppPool Performance Tab | ||
| 399 | // | ||
| 400 | if (MSI_NULL_INTEGER != psap->iIdleTimeout) | ||
| 401 | { | ||
| 402 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_IDLE_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iIdleTimeout)); | ||
| 403 | ExitOnFailure(hr, "failed to set idle timeout value"); | ||
| 404 | } | ||
| 405 | |||
| 406 | if (MSI_NULL_INTEGER != psap->iQueueLimit) | ||
| 407 | { | ||
| 408 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_UL_APPPOOL_QUEUE_LENGTH, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iQueueLimit)); | ||
| 409 | ExitOnFailure(hr, "failed to set request queue limit value"); | ||
| 410 | } | ||
| 411 | |||
| 412 | if (*psap->wzCpuMon) | ||
| 413 | { | ||
| 414 | hr = StrAllocString(&pwzValue, psap->wzCpuMon, 0); | ||
| 415 | ExitOnFailure(hr, "failed to allocate CPUMonitor string"); | ||
| 416 | |||
| 417 | DWORD dwPercent = 0; | ||
| 418 | DWORD dwRefreshMinutes = 0; | ||
| 419 | DWORD dwAction = 0; | ||
| 420 | |||
| 421 | dwPercent = wcstoul(pwzValue, &wz, 10); | ||
| 422 | if (100 < dwPercent) | ||
| 423 | { | ||
| 424 | ExitOnFailure(hr = E_INVALIDARG, "invalid maximum cpu percentage value: %d", dwPercent); | ||
| 425 | } | ||
| 426 | if (wz && L',' == *wz) | ||
| 427 | { | ||
| 428 | ++wz; | ||
| 429 | dwRefreshMinutes = wcstoul(wz, &wz, 10); | ||
| 430 | if (wz && L',' == *wz) | ||
| 431 | { | ||
| 432 | ++wz; | ||
| 433 | dwAction = wcstoul(wz, &wz, 10); | ||
| 434 | } | ||
| 435 | } | ||
| 436 | |||
| 437 | if (dwPercent) | ||
| 438 | { | ||
| 439 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_CPU_LIMIT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)(dwPercent * 1000))); | ||
| 440 | ExitOnFailure(hr, "failed to set CPU percentage max"); | ||
| 441 | } | ||
| 442 | if (dwRefreshMinutes) | ||
| 443 | { | ||
| 444 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_CPU_RESET_INTERVAL, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwRefreshMinutes)); | ||
| 445 | ExitOnFailure(hr, "failed to set refresh CPU minutes"); | ||
| 446 | } | ||
| 447 | if (dwAction) | ||
| 448 | { | ||
| 449 | // 0 = No Action | ||
| 450 | // 1 = Shutdown | ||
| 451 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_CPU_ACTION, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwAction)); | ||
| 452 | ExitOnFailure(hr, "failed to set CPU action"); | ||
| 453 | } | ||
| 454 | } | ||
| 455 | |||
| 456 | if (MSI_NULL_INTEGER != psap->iMaxProcesses) | ||
| 457 | { | ||
| 458 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_MAX_PROCESS_COUNT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iMaxProcesses)); | ||
| 459 | ExitOnFailure(hr, "failed to set web garden maximum worker processes"); | ||
| 460 | } | ||
| 461 | |||
| 462 | // TODO: Health Tab if anyone wants it? | ||
| 463 | |||
| 464 | // | ||
| 465 | // Set the AppPool Identity tab | ||
| 466 | // | ||
| 467 | if (psap->iAttributes & APATTR_NETSERVICE) | ||
| 468 | { | ||
| 469 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_NETWORKSERVICE; | ||
| 470 | } | ||
| 471 | else if (psap->iAttributes & APATTR_LOCSERVICE) | ||
| 472 | { | ||
| 473 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSERVICE; | ||
| 474 | } | ||
| 475 | else if (psap->iAttributes & APATTR_LOCSYSTEM) | ||
| 476 | { | ||
| 477 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSYSTEM; | ||
| 478 | } | ||
| 479 | else if (psap->iAttributes & APATTR_OTHERUSER) | ||
| 480 | { | ||
| 481 | if (!*psap->suUser.wzDomain || CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzDomain, -1, L".", -1)) | ||
| 482 | { | ||
| 483 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"NetworkService", -1)) | ||
| 484 | { | ||
| 485 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_NETWORKSERVICE; | ||
| 486 | } | ||
| 487 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"LocalService", -1)) | ||
| 488 | { | ||
| 489 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSERVICE; | ||
| 490 | } | ||
| 491 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"LocalSystem", -1)) | ||
| 492 | { | ||
| 493 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSYSTEM; | ||
| 494 | } | ||
| 495 | else | ||
| 496 | { | ||
| 497 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER; | ||
| 498 | } | ||
| 499 | } | ||
| 500 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzDomain, -1, L"NT AUTHORITY", -1)) | ||
| 501 | { | ||
| 502 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"NETWORK SERVICE", -1)) | ||
| 503 | { | ||
| 504 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_NETWORKSERVICE; | ||
| 505 | } | ||
| 506 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"SERVICE", -1)) | ||
| 507 | { | ||
| 508 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSERVICE; | ||
| 509 | } | ||
| 510 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"SYSTEM", -1)) | ||
| 511 | { | ||
| 512 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSYSTEM; | ||
| 513 | } | ||
| 514 | else | ||
| 515 | { | ||
| 516 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER; | ||
| 517 | } | ||
| 518 | } | ||
| 519 | else | ||
| 520 | { | ||
| 521 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER; | ||
| 522 | } | ||
| 523 | } | ||
| 524 | |||
| 525 | if (-1 != dwIdentity) | ||
| 526 | { | ||
| 527 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_IDENTITY_TYPE, METADATA_INHERIT , IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwIdentity)); | ||
| 528 | ExitOnFailure(hr, "failed to set app pool identity"); | ||
| 529 | |||
| 530 | if (MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER == dwIdentity) | ||
| 531 | { | ||
| 532 | if (*psap->suUser.wzDomain) | ||
| 533 | { | ||
| 534 | hr = StrAllocFormatted(&pwzValue, L"%s\\%s", psap->suUser.wzDomain, psap->suUser.wzName); | ||
| 535 | ExitOnFailure(hr, "failed to format user name: %ls domain: %ls", psap->suUser.wzName, psap->suUser.wzDomain); | ||
| 536 | } | ||
| 537 | else | ||
| 538 | { | ||
| 539 | hr = StrAllocFormatted(&pwzValue, L"%s", psap->suUser.wzName); | ||
| 540 | ExitOnFailure(hr, "failed to format user name: %ls", psap->suUser.wzName); | ||
| 541 | } | ||
| 542 | |||
| 543 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_WAM_USER_NAME, METADATA_INHERIT , IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)pwzValue); | ||
| 544 | ExitOnFailure(hr, "failed to set app pool identity name"); | ||
| 545 | |||
| 546 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_WAM_PWD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)psap->suUser.wzPassword); | ||
| 547 | ExitOnFailure(hr, "failed to set app pool identity password"); | ||
| 548 | } | ||
| 549 | } | ||
| 550 | |||
| 551 | LExit: | ||
| 552 | ReleaseStr(pwzValue); | ||
| 553 | |||
| 554 | return hr; | ||
| 555 | } | ||
| 556 | |||
| 557 | |||
| 558 | HRESULT ScaRemoveAppPool( | ||
| 559 | __in IMSAdminBase* piMetabase, | ||
| 560 | __in SCA_APPPOOL* psap | ||
| 561 | ) | ||
| 562 | { | ||
| 563 | Assert(piMetabase && psap); | ||
| 564 | |||
| 565 | HRESULT hr = S_OK; | ||
| 566 | |||
| 567 | // simply remove the root key and everything else is pulled at the same time | ||
| 568 | if (0 != lstrlenW(psap->wzKey)) | ||
| 569 | { | ||
| 570 | hr = ScaDeleteMetabaseKey(piMetabase, psap->wzKey, L""); | ||
| 571 | ExitOnFailure(hr, "failed to delete AppPool key: %ls", psap->wzKey); | ||
| 572 | } | ||
| 573 | |||
| 574 | // TODO: Maybe check to make sure any web sites that are using this AppPool are put back in the 'DefaultAppPool' | ||
| 575 | |||
| 576 | LExit: | ||
| 577 | return hr; | ||
| 578 | } | ||
| 579 | |||
| 580 | |||
| 581 | HRESULT AddAppPoolToList( | ||
| 582 | __in SCA_APPPOOL** ppsapList | ||
| 583 | ) | ||
| 584 | { | ||
| 585 | HRESULT hr = S_OK; | ||
| 586 | SCA_APPPOOL* psap = static_cast<SCA_APPPOOL*>(MemAlloc(sizeof(SCA_APPPOOL), TRUE)); | ||
| 587 | ExitOnNull(psap, hr, E_OUTOFMEMORY, "failed to allocate memory for new element in app pool list"); | ||
| 588 | |||
| 589 | psap->psapNext = *ppsapList; | ||
| 590 | *ppsapList = psap; | ||
| 591 | |||
| 592 | LExit: | ||
| 593 | return hr; | ||
| 594 | } | ||
