Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1717 lines
41 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. resource.c
  5. Abstract:
  6. Server side support for Cluster APIs dealing with resources
  7. Author:
  8. John Vert (jvert) 7-Mar-1996
  9. Revision History:
  10. --*/
  11. #include "apip.h"
  12. HRES_RPC
  13. s_ApiOpenResource(
  14. IN handle_t IDL_handle,
  15. IN LPCWSTR lpszResourceName,
  16. OUT error_status_t *Status
  17. )
  18. /*++
  19. Routine Description:
  20. Opens a handle to an existing resource object.
  21. Arguments:
  22. IDL_handle - RPC binding handle, not used.
  23. lpszResourceName - Supplies the name of the resource to open.
  24. Status - Returns any error that may occur.
  25. Return Value:
  26. A context handle to a resource object if successful
  27. NULL otherwise.
  28. --*/
  29. {
  30. HRES_RPC Resource;
  31. PAPI_HANDLE Handle;
  32. Handle = LocalAlloc(LMEM_FIXED, sizeof(API_HANDLE));
  33. if (Handle == NULL) {
  34. *Status = ERROR_NOT_ENOUGH_MEMORY;
  35. return(NULL);
  36. }
  37. Resource = OmReferenceObjectByName(ObjectTypeResource, lpszResourceName);
  38. if (Resource == NULL) {
  39. LocalFree(Handle);
  40. *Status = ERROR_RESOURCE_NOT_FOUND;
  41. ClRtlLogPrint(LOG_NOISE,
  42. "[API] s_ApiOpenResource: Resource %1!ws! not found, status = %2!u!...\n",
  43. lpszResourceName,
  44. *Status);
  45. return(NULL);
  46. }
  47. *Status = ERROR_SUCCESS;
  48. Handle->Type = API_RESOURCE_HANDLE;
  49. Handle->Resource = Resource;
  50. Handle->Flags = 0;
  51. InitializeListHead(&Handle->NotifyList);
  52. return(Handle);
  53. }
  54. HRES_RPC
  55. s_ApiCreateResource(
  56. IN HGROUP_RPC hGroup,
  57. IN LPCWSTR lpszResourceName,
  58. IN LPCWSTR lpszResourceType,
  59. IN DWORD dwFlags,
  60. OUT error_status_t *pStatus
  61. )
  62. /*++
  63. Routine Description:
  64. Creates a new resource object.
  65. Arguments:
  66. hGroup - Supplies the group the resource is to be created in.
  67. lpszResourceName - Supplies the name of the resource to create.
  68. lpszResourceType - Supplies the type of the resource.
  69. dwFlags - Supplies any optional flags.
  70. Status - Returns any error that may occur.
  71. Return Value:
  72. A context handle to a resource object if successful
  73. NULL otherwise.
  74. --*/
  75. {
  76. HRES_RPC Resource=NULL;
  77. PFM_GROUP Group;
  78. UUID Guid;
  79. DWORD Status = ERROR_SUCCESS;
  80. WCHAR *KeyName=NULL;
  81. HDMKEY Key=NULL;
  82. HDMKEY GroupKey=NULL;
  83. HDMKEY TypeKey = NULL;
  84. HDMKEY ParamKey;
  85. DWORD Disposition;
  86. DWORD pollIntervals = CLUSTER_RESOURCE_USE_DEFAULT_POLL_INTERVAL;
  87. PAPI_HANDLE Handle;
  88. PFM_RESTYPE ResType;
  89. DWORD dwPersistentState = 0;
  90. DWORD dwClusterHighestVersion;
  91. if (ApiState != ApiStateOnline)
  92. {
  93. *pStatus = ERROR_SHARING_PAUSED;
  94. return(NULL);
  95. }
  96. if (((PAPI_HANDLE)hGroup)->Type != API_GROUP_HANDLE)
  97. {
  98. *pStatus = ERROR_INVALID_HANDLE;
  99. return(NULL);
  100. }
  101. Group = ((PAPI_HANDLE)hGroup)->Group;
  102. //
  103. // Check for bogus flags.
  104. //
  105. if (dwFlags & ~CLUSTER_RESOURCE_VALID_FLAGS)
  106. {
  107. *pStatus = ERROR_INVALID_PARAMETER;
  108. return(NULL);
  109. }
  110. Handle = LocalAlloc(LMEM_FIXED, sizeof(API_HANDLE));
  111. if (Handle == NULL)
  112. {
  113. *pStatus = ERROR_NOT_ENOUGH_MEMORY;
  114. return(NULL);
  115. }
  116. //
  117. // Chittur Subbaraman (chitturs) - 1/30/2000
  118. //
  119. // If we are dealing with the mixed mode cluster, do the
  120. // registry updates right here since the GUM handler won't do it.
  121. //
  122. NmGetClusterOperationalVersion( &dwClusterHighestVersion,
  123. NULL,
  124. NULL );
  125. //
  126. // Open the resource type key. This validates that the specified type exists.
  127. //
  128. TypeKey = DmOpenKey(DmResourceTypesKey,
  129. lpszResourceType,
  130. KEY_READ);
  131. if (TypeKey == NULL)
  132. {
  133. Status = GetLastError();
  134. goto error_exit;
  135. }
  136. retry:
  137. //
  138. // Create a GUID for this resource.
  139. //
  140. Status = UuidCreate(&Guid);
  141. if (Status != RPC_S_OK)
  142. {
  143. goto error_exit;
  144. }
  145. Status = UuidToString(&Guid, &KeyName);
  146. if (Status != RPC_S_OK)
  147. {
  148. goto error_exit;
  149. }
  150. ClRtlLogPrint(LOG_NOISE,
  151. "[API] Creating resource %1!ws! <%2!ws!> (%3!ws!)\n",
  152. lpszResourceType,
  153. lpszResourceName,
  154. KeyName);
  155. if ( CLUSTER_GET_MAJOR_VERSION( dwClusterHighestVersion ) <
  156. NT51_MAJOR_VERSION )
  157. {
  158. //
  159. // Create the new resource key.
  160. //
  161. Key = DmCreateKey(DmResourcesKey,
  162. KeyName,
  163. 0,
  164. KEY_READ | KEY_WRITE,
  165. NULL,
  166. &Disposition);
  167. if (Key == NULL)
  168. {
  169. Status = GetLastError();
  170. goto error_exit;
  171. }
  172. if (Disposition != REG_CREATED_NEW_KEY)
  173. {
  174. ClRtlLogPrint(LOG_CRITICAL,
  175. "[API] ApiCreateResource generated GUID %1!ws! that already existed! This is impossible.\n",
  176. KeyName);
  177. DmCloseKey(Key);
  178. RpcStringFree(&KeyName);
  179. goto retry;
  180. }
  181. CL_ASSERT(Disposition == REG_CREATED_NEW_KEY);
  182. //
  183. // Set the resource's name in the registry
  184. //
  185. Status = DmSetValue(Key,
  186. CLUSREG_NAME_RES_NAME,
  187. REG_SZ,
  188. (CONST BYTE *)lpszResourceName,
  189. (lstrlenW(lpszResourceName)+1)*sizeof(WCHAR));
  190. if (Status != ERROR_SUCCESS)
  191. {
  192. goto error_exit;
  193. }
  194. //
  195. // Set the resource's type in the registry
  196. // Note we reference the resource type and use its ID
  197. // so that the case is correct.
  198. //
  199. ResType = OmReferenceObjectById(ObjectTypeResType, lpszResourceType);
  200. CL_ASSERT(ResType != NULL);
  201. lpszResourceType = OmObjectId(ResType);
  202. OmDereferenceObject(ResType);
  203. Status = DmSetValue(Key,
  204. CLUSREG_NAME_RES_TYPE,
  205. REG_SZ,
  206. (CONST BYTE *)lpszResourceType,
  207. (lstrlenW(lpszResourceType)+1)*sizeof(WCHAR));
  208. if (Status != ERROR_SUCCESS)
  209. {
  210. goto error_exit;
  211. }
  212. //
  213. // Set the resource's poll intervals in the registry.
  214. //
  215. Status = DmSetValue(Key,
  216. CLUSREG_NAME_RES_LOOKS_ALIVE,
  217. REG_DWORD,
  218. (CONST BYTE *)&pollIntervals,
  219. 4);
  220. if (Status != ERROR_SUCCESS)
  221. {
  222. goto error_exit;
  223. }
  224. Status = DmSetValue(Key,
  225. CLUSREG_NAME_RES_IS_ALIVE,
  226. REG_DWORD,
  227. (CONST BYTE *)&pollIntervals,
  228. 4);
  229. if (Status != ERROR_SUCCESS)
  230. {
  231. goto error_exit;
  232. }
  233. //
  234. // If this resource should be started in a separate monitor, set that
  235. // parameter now.
  236. //
  237. if (dwFlags & CLUSTER_RESOURCE_SEPARATE_MONITOR)
  238. {
  239. DWORD SeparateMonitor = 1;
  240. Status = DmSetValue(Key,
  241. CLUSREG_NAME_RES_SEPARATE_MONITOR,
  242. REG_DWORD,
  243. (CONST BYTE *)&SeparateMonitor,
  244. sizeof(SeparateMonitor));
  245. if (Status != ERROR_SUCCESS)
  246. {
  247. goto error_exit;
  248. }
  249. }
  250. //
  251. // Create a Parameters key for the resource.
  252. //
  253. ParamKey = DmCreateKey(Key,
  254. CLUSREG_KEYNAME_PARAMETERS,
  255. 0,
  256. KEY_READ,
  257. NULL,
  258. &Disposition);
  259. if (ParamKey == NULL)
  260. {
  261. CL_LOGFAILURE(GetLastError());
  262. } else
  263. {
  264. DmCloseKey(ParamKey);
  265. }
  266. GroupKey = DmOpenKey(DmGroupsKey, OmObjectId(Group), KEY_READ | KEY_WRITE);
  267. if (GroupKey == NULL)
  268. {
  269. Status = GetLastError();
  270. goto error_exit;
  271. }
  272. //
  273. // Chittur Subbaraman (chitturs) - 5/25/99
  274. //
  275. // Make sure you set the persistent state of the resource to
  276. // ClusterResourceOffline before you create the resource. If
  277. // this is not done, if you create a resource in a group which
  278. // is online, the group's persistent state value (i.e., 1 in
  279. // this case) is inherited by the resource in FmpQueryResourceInfo
  280. // (only the memory state is set and not the registry state and
  281. // this was a problem as well) and if you move such a group to
  282. // another node, it will bring the newly created resource online.
  283. //
  284. Status = DmSetValue( Key,
  285. CLUSREG_NAME_RES_PERSISTENT_STATE,
  286. REG_DWORD,
  287. ( CONST BYTE * )&dwPersistentState,
  288. sizeof( DWORD ) );
  289. if ( Status != ERROR_SUCCESS )
  290. {
  291. goto error_exit;
  292. }
  293. }
  294. Resource = FmCreateResource(Group, KeyName, lpszResourceName, lpszResourceType, dwFlags);
  295. if (Resource == NULL)
  296. {
  297. Status = GetLastError();
  298. if (Status == ERROR_ALREADY_EXISTS)
  299. {
  300. RpcStringFree(&KeyName);
  301. goto retry;
  302. }
  303. goto error_exit;
  304. }
  305. if ( CLUSTER_GET_MAJOR_VERSION( dwClusterHighestVersion ) <
  306. NT51_MAJOR_VERSION )
  307. {
  308. //
  309. // Add the resource to the Contains value of the specified group.
  310. //
  311. Status = DmAppendToMultiSz(GroupKey,
  312. CLUSREG_NAME_GRP_CONTAINS,
  313. KeyName);
  314. if (Status != ERROR_SUCCESS)
  315. {
  316. //
  317. // BUGBUG John Vert (jvert) 3-May-1996
  318. // Need to delete this from the FM!
  319. //
  320. OmDereferenceObject(Resource);
  321. Resource = NULL;
  322. }
  323. }
  324. error_exit:
  325. if ( CLUSTER_GET_MAJOR_VERSION( dwClusterHighestVersion ) <
  326. NT51_MAJOR_VERSION )
  327. {
  328. if (Key != NULL)
  329. {
  330. if (Status != ERROR_SUCCESS)
  331. {
  332. //
  333. // Try and cleanup the key we just created.
  334. //
  335. DmDeleteKey(Key, CLUSREG_KEYNAME_PARAMETERS);
  336. DmDeleteKey(DmResourcesKey, KeyName);
  337. }
  338. DmCloseKey(Key);
  339. }
  340. if (GroupKey != NULL)
  341. {
  342. DmCloseKey(GroupKey);
  343. }
  344. }
  345. if (TypeKey != NULL)
  346. {
  347. DmCloseKey(TypeKey);
  348. }
  349. if (KeyName != NULL)
  350. {
  351. RpcStringFree(&KeyName);
  352. }
  353. *pStatus = Status;
  354. if (Status != ERROR_SUCCESS)
  355. {
  356. LocalFree(Handle);
  357. return(NULL);
  358. }
  359. CL_ASSERT(Resource != NULL);
  360. Handle->Type = API_RESOURCE_HANDLE;
  361. Handle->Resource = Resource;
  362. Handle->Flags = 0;
  363. InitializeListHead(&Handle->NotifyList);
  364. return(Handle);
  365. }
  366. error_status_t
  367. s_ApiDeleteResource(
  368. IN HRES_RPC hResource
  369. )
  370. /*++
  371. Routine Description:
  372. Deletes the specified cluster resource from the group. The resource
  373. must have no other resources dependent on it.
  374. Arguments:
  375. hResource - Supplies the cluster resource to be deleted.
  376. Return Value:
  377. If the function succeeds, the return value is ERROR_SUCCESS.
  378. If the function fails, the return value is an error value.
  379. --*/
  380. {
  381. PFM_RESOURCE Resource;
  382. DWORD Status;
  383. HDMKEY Key;
  384. HDMKEY GroupKey;
  385. DWORD dwClusterHighestVersion;
  386. API_CHECK_INIT();
  387. VALIDATE_RESOURCE_EXISTS(Resource, hResource);
  388. //
  389. // Chittur Subbaraman (chitturs) - 09/07/2000
  390. //
  391. // If we are dealing with a Whistler-Win2K cluster, do the
  392. // registry updates right here since the GUM handler won't do it.
  393. //
  394. NmGetClusterOperationalVersion( &dwClusterHighestVersion,
  395. NULL,
  396. NULL );
  397. Status = FmDeleteResource(Resource);
  398. if ( ( Status == ERROR_SUCCESS ) &&
  399. ( CLUSTER_GET_MAJOR_VERSION( dwClusterHighestVersion ) <
  400. NT51_MAJOR_VERSION ) ) {
  401. Status = DmDeleteTree(DmResourcesKey,OmObjectId(Resource));
  402. if ( (Status != ERROR_SUCCESS) &&
  403. (Status != ERROR_FILE_NOT_FOUND) ) {
  404. CL_LOGFAILURE( Status );
  405. return(Status);
  406. }
  407. GroupKey = DmOpenKey(DmGroupsKey,
  408. OmObjectId(Resource->Group),
  409. KEY_READ | KEY_SET_VALUE);
  410. if (GroupKey != NULL) {
  411. DmRemoveFromMultiSz(GroupKey,
  412. CLUSREG_NAME_GRP_CONTAINS,
  413. OmObjectId(Resource));
  414. DmCloseKey(GroupKey);
  415. }
  416. }
  417. return(Status);
  418. }
  419. error_status_t
  420. s_ApiCloseResource(
  421. IN OUT HRES_RPC *phResource
  422. )
  423. /*++
  424. Routine Description:
  425. Closes an open resource context handle.
  426. Arguments:
  427. Resource - Supplies a pointer to the HRES_RPC to be closed.
  428. Returns NULL
  429. Return Value:
  430. None.
  431. --*/
  432. {
  433. PFM_RESOURCE Resource;
  434. PAPI_HANDLE Handle;
  435. VALIDATE_RESOURCE(Resource, *phResource);
  436. Handle = (PAPI_HANDLE)*phResource;
  437. ApipRundownNotify(Handle);
  438. OmDereferenceObject(Resource);
  439. LocalFree(*phResource);
  440. *phResource = NULL;
  441. return(ERROR_SUCCESS);
  442. }
  443. VOID
  444. HRES_RPC_rundown(
  445. IN HRES_RPC Resource
  446. )
  447. /*++
  448. Routine Description:
  449. RPC rundown procedure for a HRES_RPC. Just closes the handle.
  450. Arguments:
  451. Resource - Supplies the HRES_RPC that is to be rundown.
  452. Return Value:
  453. None.
  454. --*/
  455. {
  456. s_ApiCloseResource(&Resource);
  457. }
  458. error_status_t
  459. s_ApiGetResourceState(
  460. IN HRES_RPC hResource,
  461. OUT DWORD *lpState,
  462. OUT LPWSTR *lpNodeId,
  463. OUT LPWSTR *lpGroupName
  464. )
  465. /*++
  466. Routine Description:
  467. Returns the current state of the specified resource.
  468. Arguments:
  469. hResource - Supplies the resource whose state is to be returned.
  470. lpState - Returns the current state of the resource
  471. lpNodeId - Returns the Id of the node where the resource is currently online
  472. lpGroupName - Returns the name of the group the the resource is a member of
  473. Return Value:
  474. ERROR_SUCCESS if successful
  475. Win32 error code otherwise
  476. --*/
  477. {
  478. PFM_RESOURCE Resource;
  479. LPWSTR NodeId;
  480. DWORD IdLength;
  481. VALIDATE_RESOURCE_EXISTS(Resource, hResource);
  482. IdLength = MAX_COMPUTERNAME_LENGTH+1;
  483. NodeId = MIDL_user_allocate(IdLength*sizeof(WCHAR));
  484. if (NodeId == NULL) {
  485. return(ERROR_NOT_ENOUGH_MEMORY);
  486. }
  487. *lpState = FmGetResourceState( Resource,
  488. NodeId,
  489. &IdLength);
  490. if ( *lpState == ClusterResourceStateUnknown ) {
  491. MIDL_user_free(NodeId);
  492. return(GetLastError());
  493. }
  494. *lpNodeId = NodeId;
  495. *lpGroupName = ApipGetObjectName(Resource->Group);
  496. return(ERROR_SUCCESS);
  497. }
  498. error_status_t
  499. s_ApiSetResourceName(
  500. IN HRES_RPC hResource,
  501. IN LPCWSTR lpszResourceName
  502. )
  503. /*++
  504. Routine Description:
  505. Sets the new friendly name of a resource.
  506. Arguments:
  507. hResource - Supplies the resource whose name is to be set.
  508. lpszResourceName - Supplies the new name of hResource
  509. Return Value:
  510. ERROR_SUCCESS if successful
  511. Win32 error code otherwise
  512. --*/
  513. {
  514. PFM_RESOURCE Resource;
  515. DWORD Status;
  516. API_CHECK_INIT();
  517. VALIDATE_RESOURCE_EXISTS(Resource, hResource);
  518. //
  519. // Tell the FM about the new name. If it is OK with the
  520. // FM, go ahead and update the registry.
  521. //
  522. Status = FmSetResourceName(Resource,
  523. lpszResourceName);
  524. return(Status);
  525. }
  526. error_status_t
  527. s_ApiGetResourceId(
  528. IN HRES_RPC hResource,
  529. OUT LPWSTR *pGuid
  530. )
  531. /*++
  532. Routine Description:
  533. Returns the unique identifier (GUID) for a resource.
  534. Arguments:
  535. hResource - Supplies the resource whose identifer is to be returned
  536. pGuid - Returns the unique identifier. This memory must be freed on the
  537. client side.
  538. Return Value:
  539. ERROR_SUCCESS if successful
  540. Win32 error code otherwise.
  541. --*/
  542. {
  543. PFM_RESOURCE Resource;
  544. DWORD NameLen;
  545. LPCWSTR Name;
  546. VALIDATE_RESOURCE_EXISTS(Resource, hResource);
  547. Name = OmObjectId(Resource);
  548. NameLen = (lstrlenW(Name)+1)*sizeof(WCHAR);
  549. *pGuid = MIDL_user_allocate(NameLen);
  550. if (*pGuid == NULL) {
  551. return(ERROR_NOT_ENOUGH_MEMORY);
  552. }
  553. CopyMemory(*pGuid, Name, NameLen);
  554. return(ERROR_SUCCESS);
  555. }
  556. error_status_t
  557. s_ApiGetResourceType(
  558. IN HRES_RPC hResource,
  559. OUT LPWSTR *lpszResourceType
  560. )
  561. /*++
  562. Routine Description:
  563. Returns the resource type for a resource.
  564. Arguments:
  565. hResource - Supplies the resource whose identifer is to be returned
  566. lpszResourceType - Returns the resource type name. This memory must be
  567. freed on the client side.
  568. Return Value:
  569. ERROR_SUCCESS if successful
  570. Win32 error code otherwise.
  571. --*/
  572. {
  573. PFM_RESOURCE Resource;
  574. DWORD NameLen;
  575. LPCWSTR Name;
  576. VALIDATE_RESOURCE_EXISTS(Resource, hResource);
  577. if ( Resource->Type == NULL ) {
  578. return(ERROR_INVALID_STATE);
  579. }
  580. Name = OmObjectId(Resource->Type);
  581. NameLen = (lstrlenW(Name)+1)*sizeof(WCHAR);
  582. *lpszResourceType = MIDL_user_allocate(NameLen);
  583. if (*lpszResourceType == NULL) {
  584. return(ERROR_NOT_ENOUGH_MEMORY);
  585. }
  586. CopyMemory(*lpszResourceType, Name, NameLen);
  587. return(ERROR_SUCCESS);
  588. }
  589. DWORD
  590. s_ApiOnlineResource(
  591. IN HRES_RPC hResource
  592. )
  593. /*++
  594. Routine Description:
  595. Brings a resource and all its dependencies online
  596. Arguments:
  597. hResource - Supplies the resource to be brought online
  598. Return Value:
  599. ERROR_SUCCESS if successful
  600. Win32 error code otherwise
  601. --*/
  602. {
  603. PFM_RESOURCE Resource;
  604. API_CHECK_INIT();
  605. VALIDATE_RESOURCE(Resource, hResource);
  606. return(FmOnlineResource(Resource));
  607. }
  608. DWORD
  609. s_ApiFailResource(
  610. IN HRES_RPC hResource
  611. )
  612. /*++
  613. Routine Description:
  614. Initiates a resource failure. The specified resource is treated as failed.
  615. This causes the cluster to initiate the same failover process that would
  616. result if the resource actually failed.
  617. Arguments:
  618. hResource - Supplies the resource to be failed over
  619. Return Value:
  620. ERROR_SUCCESS if successful
  621. Win32 error code otherwise
  622. --*/
  623. {
  624. PFM_RESOURCE Resource;
  625. API_CHECK_INIT();
  626. VALIDATE_RESOURCE_EXISTS(Resource, hResource);
  627. return(FmFailResource(Resource));
  628. }
  629. DWORD
  630. s_ApiOfflineResource(
  631. IN HRES_RPC hResource
  632. )
  633. /*++
  634. Routine Description:
  635. Brings a resource and all its dependents offline
  636. Arguments:
  637. hResource - Supplies the resource to be brought offline
  638. Return Value:
  639. ERROR_SUCCESS if successful
  640. Win32 error code otherwise
  641. --*/
  642. {
  643. PFM_RESOURCE Resource;
  644. API_CHECK_INIT();
  645. VALIDATE_RESOURCE_EXISTS(Resource, hResource);
  646. return(FmOfflineResource(Resource));
  647. }
  648. error_status_t
  649. s_ApiAddResourceDependency(
  650. IN HRES_RPC hResource,
  651. IN HRES_RPC hDependsOn
  652. )
  653. /*++
  654. Routine Description:
  655. Adds a dependency relationship to a given resource. Both
  656. resources must be in the same group.
  657. Arguments:
  658. hResource - Supplies the resource which is dependent.
  659. hDependsOn - Supplies the resource that hResource depends on.
  660. Return Value:
  661. ERROR_SUCCESS if successful.
  662. Win32 error code otherwise.
  663. --*/
  664. {
  665. PFM_RESOURCE Resource;
  666. PFM_RESOURCE DependsOn;
  667. DWORD Status;
  668. HDMKEY ResKey;
  669. API_CHECK_INIT();
  670. VALIDATE_RESOURCE_EXISTS(Resource, hResource);
  671. VALIDATE_RESOURCE_EXISTS(DependsOn, hDependsOn);
  672. //
  673. // Call the FM to create the dependency relationship.
  674. //
  675. Status = FmAddResourceDependency(Resource, DependsOn);
  676. if (Status == ERROR_SUCCESS) {
  677. //
  678. // Add the dependency information to the cluster database.
  679. //
  680. ResKey = DmOpenKey(DmResourcesKey,
  681. OmObjectId(Resource),
  682. KEY_READ | KEY_SET_VALUE);
  683. if (ResKey == NULL) {
  684. Status = GetLastError();
  685. CL_LOGFAILURE(Status);
  686. } else {
  687. Status = DmAppendToMultiSz(ResKey,
  688. CLUSREG_NAME_RES_DEPENDS_ON,
  689. OmObjectId(DependsOn));
  690. DmCloseKey(ResKey);
  691. }
  692. if (Status != ERROR_SUCCESS) {
  693. FmRemoveResourceDependency(Resource, DependsOn);
  694. }
  695. }
  696. return(Status);
  697. }
  698. error_status_t
  699. s_ApiRemoveResourceDependency(
  700. IN HRES_RPC hResource,
  701. IN HRES_RPC hDependsOn
  702. )
  703. /*++
  704. Routine Description:
  705. Removes a dependency relationship to a given resource. Both
  706. resources must be in the same group.
  707. Arguments:
  708. hResource - Supplies the resource which is dependent.
  709. hDependsOn - Supplies the resource that hResource depends on.
  710. Return Value:
  711. ERROR_SUCCESS if successful.
  712. Win32 error code otherwise.
  713. --*/
  714. {
  715. PFM_RESOURCE Resource;
  716. PFM_RESOURCE DependsOn;
  717. DWORD Status;
  718. HDMKEY ResKey;
  719. API_CHECK_INIT();
  720. VALIDATE_RESOURCE_EXISTS(Resource, hResource);
  721. VALIDATE_RESOURCE_EXISTS(DependsOn, hDependsOn);
  722. //
  723. // If the resources are not in the same group, fail the
  724. // call. Also fail if some one tries to make a resource
  725. // dependent upon itself.
  726. //
  727. if ((Resource->Group != DependsOn->Group) ||
  728. (Resource == DependsOn)) {
  729. return(ERROR_DEPENDENCY_NOT_FOUND);
  730. }
  731. //
  732. // Remove the dependency from the registry database.
  733. //
  734. ResKey = DmOpenKey(DmResourcesKey,
  735. OmObjectId(Resource),
  736. KEY_READ | KEY_SET_VALUE);
  737. if (ResKey == NULL) {
  738. Status = GetLastError();
  739. CL_LOGFAILURE(Status);
  740. } else {
  741. Status = DmRemoveFromMultiSz(ResKey,
  742. CLUSREG_NAME_RES_DEPENDS_ON,
  743. OmObjectId(DependsOn));
  744. DmCloseKey(ResKey);
  745. }
  746. if (Status == ERROR_SUCCESS) {
  747. //
  748. // Call the FM to remove the dependency relationship.
  749. //
  750. Status = FmRemoveResourceDependency(Resource, DependsOn);
  751. } else if (Status == ERROR_FILE_NOT_FOUND) {
  752. //
  753. // Map this expected error to something a little more reasonable.
  754. //
  755. Status = ERROR_DEPENDENCY_NOT_FOUND;
  756. }
  757. return(Status);
  758. }
  759. error_status_t
  760. s_ApiCanResourceBeDependent(
  761. IN HRES_RPC hResource,
  762. IN HRES_RPC hResourceDependent
  763. )
  764. /*++
  765. Routine Description:
  766. Determines if the resource identified by hResource can depend on hResourceDependent.
  767. In order for this to be true, both resources must be members of the same group and
  768. the resource identified by hResourceDependent cannot depend on the resource identified
  769. by hResource, whether directly or indirectly.
  770. Arguments:
  771. hResource - Supplies a handle to the resource to be dependent.
  772. hResourceDependent - Supplies a handle to the resource on which
  773. the resource identified by hResource can depend.
  774. Return Value:
  775. If the resource identified by hResource can depend on the resource
  776. identified by hResourceDependent, the return value is ERROR_SUCCESS.
  777. Otherwise, the return value is ERROR_DEPENDENCY_ALREADY_EXISTS.
  778. --*/
  779. {
  780. PFM_RESOURCE Resource;
  781. PFM_RESOURCE ResourceDependent;
  782. VALIDATE_RESOURCE_EXISTS(Resource, hResource);
  783. VALIDATE_RESOURCE_EXISTS(ResourceDependent, hResourceDependent);
  784. if (Resource == ResourceDependent) {
  785. //
  786. // The caller is confused and is trying to make something
  787. // depend on itself.
  788. //
  789. return(ERROR_DEPENDENCY_ALREADY_EXISTS);
  790. }
  791. if (Resource->Group != ResourceDependent->Group) {
  792. //
  793. // The caller is confused and is trying to make something
  794. // depend on a resource in another group.
  795. //
  796. return(ERROR_DEPENDENCY_ALREADY_EXISTS);
  797. }
  798. if (FmDependentResource(ResourceDependent, Resource, FALSE)) {
  799. return(ERROR_DEPENDENCY_ALREADY_EXISTS);
  800. } else {
  801. //
  802. // Finally check to make sure an immediate dependency does
  803. // not already exist.
  804. //
  805. if (FmDependentResource(Resource, ResourceDependent, TRUE)) {
  806. return(ERROR_DEPENDENCY_ALREADY_EXISTS);
  807. } else {
  808. return(ERROR_SUCCESS);
  809. }
  810. }
  811. }
  812. error_status_t
  813. s_ApiCreateResEnum(
  814. IN HRES_RPC hResource,
  815. IN DWORD dwType,
  816. OUT PENUM_LIST *ReturnEnum
  817. )
  818. /*++
  819. Routine Description:
  820. Enumerates all the specified resource properties and returns the
  821. list of objects to the caller. The client-side is responsible
  822. for freeing the allocated memory.
  823. Arguments:
  824. hResource - Supplies the resource whose properties are to be
  825. enumerated.
  826. dwType - Supplies the type of properties to be enumerated.
  827. ReturnEnum - Returns the requested objects.
  828. Return Value:
  829. ERROR_SUCCESS if successful
  830. Win32 error code otherwise.
  831. --*/
  832. {
  833. DWORD Status;
  834. DWORD Allocated = 0;
  835. PENUM_LIST Enum = NULL;
  836. PENUM_LIST NewEnum = NULL;
  837. DWORD i;
  838. DWORD Result;
  839. PFM_RESOURCE Resource;
  840. PFM_RESOURCE Target;
  841. PNM_NODE Node;
  842. LPWSTR RealName;
  843. if (dwType & ~CLUSTER_RESOURCE_ENUM_ALL) {
  844. return(ERROR_INVALID_PARAMETER);
  845. }
  846. VALIDATE_RESOURCE_EXISTS(Resource, hResource);
  847. Allocated = INITIAL_ENUM_LIST_ALLOCATION;
  848. Enum = MIDL_user_allocate(ENUM_SIZE(Allocated));
  849. if (Enum == NULL) {
  850. Status = ERROR_NOT_ENOUGH_MEMORY;
  851. goto ErrorExit;
  852. }
  853. Enum->EntryCount = 0;
  854. //
  855. // Enumerate all dependencies.
  856. //
  857. if (dwType & CLUSTER_RESOURCE_ENUM_DEPENDS) {
  858. i=0;
  859. do {
  860. Result = FmEnumResourceDependent(Resource,
  861. i,
  862. &Target);
  863. if (Result == ERROR_SUCCESS) {
  864. RealName = ApipGetObjectName( Target );
  865. if (RealName != NULL) {
  866. ApipAddToEnum(&Enum,
  867. &Allocated,
  868. RealName,
  869. CLUSTER_RESOURCE_ENUM_DEPENDS);
  870. MIDL_user_free(RealName);
  871. }
  872. OmDereferenceObject(Target);
  873. ++i;
  874. }
  875. } while ( Result == ERROR_SUCCESS );
  876. }
  877. //
  878. // Enumerate all dependents
  879. //
  880. if (dwType & CLUSTER_RESOURCE_ENUM_PROVIDES) {
  881. i=0;
  882. do {
  883. Result = FmEnumResourceProvider(Resource,
  884. i,
  885. &Target);
  886. if (Result == ERROR_SUCCESS) {
  887. RealName = ApipGetObjectName( Target );
  888. if (RealName != NULL) {
  889. ApipAddToEnum(&Enum,
  890. &Allocated,
  891. RealName,
  892. CLUSTER_RESOURCE_ENUM_PROVIDES);
  893. MIDL_user_free(RealName);
  894. }
  895. OmDereferenceObject(Target);
  896. ++i;
  897. }
  898. } while ( Result == ERROR_SUCCESS );
  899. }
  900. //
  901. // Enumerate all possible nodes
  902. //
  903. if (dwType & CLUSTER_RESOURCE_ENUM_NODES) {
  904. i=0;
  905. do {
  906. Result = FmEnumResourceNode(Resource,
  907. i,
  908. &Node);
  909. if (Result == ERROR_SUCCESS) {
  910. RealName = (LPWSTR)OmObjectName( Node );
  911. if (RealName != NULL) {
  912. ApipAddToEnum(&Enum,
  913. &Allocated,
  914. RealName,
  915. CLUSTER_RESOURCE_ENUM_NODES);
  916. }
  917. OmDereferenceObject(Node);
  918. ++i;
  919. }
  920. } while ( Result == ERROR_SUCCESS );
  921. }
  922. *ReturnEnum = Enum;
  923. return(ERROR_SUCCESS);
  924. ErrorExit:
  925. if (Enum != NULL) {
  926. MIDL_user_free(Enum);
  927. }
  928. if (NewEnum != NULL) {
  929. MIDL_user_free(NewEnum);
  930. }
  931. *ReturnEnum = NULL;
  932. return(Status);
  933. }
  934. error_status_t
  935. s_ApiAddResourceNode(
  936. IN HRES_RPC hResource,
  937. IN HNODE_RPC hNode
  938. )
  939. /*++
  940. Routine Description:
  941. Adds a node to the list of nodes where the specified resource
  942. can be brought online.
  943. Arguments:
  944. hResource - Supplies the resource whose list of possible nodes is
  945. to be modified.
  946. hNode - Supplies the node to be added to the resource's list.
  947. Return Value:
  948. ERROR_SUCCESS if successful
  949. Win32 error code otherwise
  950. --*/
  951. {
  952. PFM_RESOURCE Resource;
  953. PNM_NODE Node;
  954. DWORD Status;
  955. DWORD dwUserModified;
  956. API_CHECK_INIT();
  957. VALIDATE_NODE(Node, hNode);
  958. VALIDATE_RESOURCE_EXISTS(Resource, hResource);
  959. //
  960. // Call the FM to do the real work.
  961. //
  962. Status = FmChangeResourceNode(Resource, Node, TRUE);
  963. if (Status != ERROR_SUCCESS) {
  964. return(Status);
  965. }
  966. //write out the fact that the user has explicitly set the
  967. //resource possible node list
  968. //
  969. dwUserModified = 1;
  970. ClRtlLogPrint(LOG_NOISE,
  971. "[API] s_ApiAddResourceNode: Setting UserModifiedPossibleNodeList key for resource %1!ws! \r\n",
  972. OmObjectId(Resource));
  973. DmSetValue( Resource->RegistryKey,
  974. CLUSREG_NAME_RES_USER_MODIFIED_POSSIBLE_LIST,
  975. REG_DWORD,
  976. (LPBYTE)&dwUserModified,
  977. sizeof(DWORD));
  978. return(Status);
  979. }
  980. error_status_t
  981. s_ApiRemoveResourceNode(
  982. IN HRES_RPC hResource,
  983. IN HNODE_RPC hNode
  984. )
  985. /*++
  986. Routine Description:
  987. Removes a node from the list of nodes that can host the
  988. specified resource. The resource must not be currently
  989. online on the specified node.
  990. Arguments:
  991. hResource - Supplies the resource whose list of possible nodes is
  992. to be modified.
  993. hNode - Supplies the node to be removed from the resource's list.
  994. Return Value:
  995. ERROR_SUCCESS if successful
  996. Win32 error code otherwise
  997. --*/
  998. {
  999. PFM_RESOURCE Resource;
  1000. PNM_NODE Node;
  1001. DWORD Status;
  1002. DWORD dwUserModified;
  1003. API_CHECK_INIT();
  1004. VALIDATE_NODE(Node, hNode);
  1005. VALIDATE_RESOURCE_EXISTS(Resource, hResource);
  1006. //
  1007. // Call the FM to do the real work.
  1008. //
  1009. Status = FmChangeResourceNode(Resource, Node, FALSE);
  1010. if (Status != ERROR_SUCCESS) {
  1011. return(Status);
  1012. }
  1013. //write out the fact that the user has explicitly set the
  1014. //resource possible node list
  1015. //
  1016. dwUserModified = 1;
  1017. ClRtlLogPrint(LOG_NOISE,
  1018. "[API] s_ApiRemoveResourceNode: Setting UserModifiedPossibleNodeList key for resource %1!ws! \r\n",
  1019. OmObjectId(Resource));
  1020. DmSetValue( Resource->RegistryKey,
  1021. CLUSREG_NAME_RES_USER_MODIFIED_POSSIBLE_LIST,
  1022. REG_DWORD,
  1023. (LPBYTE)&dwUserModified,
  1024. sizeof(DWORD));
  1025. //SS: moved the write to the registry settings to the fm
  1026. // layer as well, this way it is truly transactional
  1027. return(Status);
  1028. }
  1029. error_status_t
  1030. s_ApiCreateResourceType(
  1031. IN handle_t IDL_handle,
  1032. IN LPCWSTR lpszTypeName,
  1033. IN LPCWSTR lpszDisplayName,
  1034. IN LPCWSTR lpszDllName,
  1035. IN DWORD dwLooksAlive,
  1036. IN DWORD dwIsAlive
  1037. )
  1038. /*++
  1039. Routine Description:
  1040. Creates a new resource type in the cluster. Note that this API only
  1041. defines the resource type in the cluster registry and registers the
  1042. resource type with the cluster service. The calling program is
  1043. responsible for installing the resource type DLL on each node in the
  1044. cluster.
  1045. Arguments:
  1046. IDL_handle - RPC binding handle, not used.
  1047. lpszResourceTypeName - Supplies the new resource types name. The
  1048. specified name must be unique within the cluster.
  1049. lpszDisplayName - Supplies the display name for the new resource
  1050. type. While lpszResourceTypeName should uniquely identify the
  1051. resource type on all clusters, the lpszDisplayName should be
  1052. a localized friendly name for the resource, suitable for displaying
  1053. to administrators
  1054. lpszResourceTypeDll - Supplies the name of the new resource types DLL.
  1055. dwLooksAlive - Supplies the default LooksAlive poll interval
  1056. for the new resource type in milliseconds.
  1057. dwIsAlive - Supplies the default IsAlive poll interval for
  1058. the new resource type in milliseconds.
  1059. Return Value:
  1060. ERROR_SUCCESS if successful
  1061. Win32 error code otherwise
  1062. --*/
  1063. {
  1064. DWORD Status;
  1065. HDMKEY TypeKey = NULL;
  1066. DWORD Disposition;
  1067. DWORD dwClusterHighestVersion;
  1068. //
  1069. // Chittur Subbaraman (chitturs) - 2/8/2000
  1070. //
  1071. // If we are dealing with the mixed mode cluster, do the
  1072. // registry updates right here since the GUM handler won't do it.
  1073. //
  1074. NmGetClusterOperationalVersion( &dwClusterHighestVersion,
  1075. NULL,
  1076. NULL );
  1077. if ( CLUSTER_GET_MAJOR_VERSION( dwClusterHighestVersion ) <
  1078. NT51_MAJOR_VERSION ) {
  1079. //
  1080. // Add the resource information to the registry. If the key does not already
  1081. // exist, then the name is unique and we can go ahead and call the FM to
  1082. // create the actual resource type object.
  1083. //
  1084. TypeKey = DmCreateKey(DmResourceTypesKey,
  1085. lpszTypeName,
  1086. 0,
  1087. KEY_READ | KEY_WRITE,
  1088. NULL,
  1089. &Disposition);
  1090. if (TypeKey == NULL) {
  1091. return(GetLastError());
  1092. }
  1093. if (Disposition != REG_CREATED_NEW_KEY) {
  1094. DmCloseKey(TypeKey);
  1095. return(ERROR_ALREADY_EXISTS);
  1096. }
  1097. Status = DmSetValue(TypeKey,
  1098. CLUSREG_NAME_RESTYPE_DLL_NAME,
  1099. REG_SZ,
  1100. (CONST BYTE *)lpszDllName,
  1101. (lstrlenW(lpszDllName)+1)*sizeof(WCHAR));
  1102. if (Status != ERROR_SUCCESS) {
  1103. goto error_exit;
  1104. }
  1105. Status = DmSetValue(TypeKey,
  1106. CLUSREG_NAME_RESTYPE_IS_ALIVE,
  1107. REG_DWORD,
  1108. (CONST BYTE *)&dwIsAlive,
  1109. sizeof(dwIsAlive));
  1110. if (Status != ERROR_SUCCESS) {
  1111. goto error_exit;
  1112. }
  1113. Status = DmSetValue(TypeKey,
  1114. CLUSREG_NAME_RESTYPE_LOOKS_ALIVE,
  1115. REG_DWORD,
  1116. (CONST BYTE *)&dwLooksAlive,
  1117. sizeof(dwIsAlive));
  1118. if (Status != ERROR_SUCCESS) {
  1119. goto error_exit;
  1120. }
  1121. Status = DmSetValue(TypeKey,
  1122. CLUSREG_NAME_RESTYPE_NAME,
  1123. REG_SZ,
  1124. (CONST BYTE *)lpszDisplayName,
  1125. (lstrlenW(lpszDisplayName)+1)*sizeof(WCHAR));
  1126. if (Status != ERROR_SUCCESS) {
  1127. goto error_exit;
  1128. }
  1129. }
  1130. Status = FmCreateResourceType(lpszTypeName,
  1131. lpszDisplayName,
  1132. lpszDllName,
  1133. dwLooksAlive,
  1134. dwIsAlive);
  1135. if (Status != ERROR_SUCCESS) {
  1136. goto error_exit;
  1137. }
  1138. if (TypeKey != NULL) {
  1139. DmCloseKey(TypeKey);
  1140. }
  1141. return(ERROR_SUCCESS);
  1142. error_exit:
  1143. if ( CLUSTER_GET_MAJOR_VERSION( dwClusterHighestVersion ) <
  1144. NT51_MAJOR_VERSION ) {
  1145. DmCloseKey(TypeKey);
  1146. DmDeleteKey(DmResourceTypesKey, lpszTypeName);
  1147. }
  1148. return(Status);
  1149. }
  1150. error_status_t
  1151. s_ApiDeleteResourceType(
  1152. IN handle_t IDL_handle,
  1153. IN LPCWSTR lpszTypeName
  1154. )
  1155. /*++
  1156. Routine Description:
  1157. Deletes a resource type in the cluster. Note that this API only
  1158. deletes the resource type in the cluster registry and unregisters the
  1159. resource type with the cluster service. The calling program is
  1160. responsible for deleting the resource type DLL on each node in the
  1161. cluster. If any resources of the specified type exist, this API
  1162. fails. The calling program is responsible for deleting any resources
  1163. of this type before deleting the resource type.
  1164. Arguments:
  1165. IDL_handle - RPC binding handle, not used.
  1166. lpszResourceTypeName - Supplies the name of the resource type to
  1167. be deleted.
  1168. Return Value:
  1169. ERROR_SUCCESS if successful
  1170. Win32 error code otherwise
  1171. --*/
  1172. {
  1173. DWORD Status;
  1174. //
  1175. // Delete the resource from the FM. This will check to make sure no
  1176. // resources of the specified type exist and check that the resource
  1177. // is already installed.
  1178. //
  1179. Status = FmDeleteResourceType(lpszTypeName);
  1180. if (Status != ERROR_SUCCESS) {
  1181. return(Status);
  1182. }
  1183. //
  1184. // Now remove the resource type from the registry.
  1185. //
  1186. DmDeleteTree(DmResourceTypesKey, lpszTypeName);
  1187. return(ERROR_SUCCESS);
  1188. }
  1189. error_status_t
  1190. s_ApiChangeResourceGroup(
  1191. IN HRES_RPC hResource,
  1192. IN HGROUP_RPC hGroup
  1193. )
  1194. /*++
  1195. Routine Description:
  1196. Moves a resource from one group to another.
  1197. Arguments:
  1198. hResource - Supplies the resource to move.
  1199. hGroup - Supplies the new group that the resource should be in.
  1200. Return Value:
  1201. ERROR_SUCCESS if successful
  1202. Win32 error code otherwise.
  1203. --*/
  1204. {
  1205. PFM_RESOURCE Resource;
  1206. PFM_GROUP Group;
  1207. DWORD Status;
  1208. API_CHECK_INIT();
  1209. VALIDATE_RESOURCE_EXISTS(Resource, hResource);
  1210. VALIDATE_GROUP_EXISTS(Group, hGroup);
  1211. //
  1212. // Call the FM to do the real work.
  1213. //
  1214. Status = FmChangeResourceGroup(Resource, Group);
  1215. if (Status != ERROR_SUCCESS) {
  1216. goto FnExit;
  1217. }
  1218. FnExit:
  1219. return(Status);
  1220. }
  1221. /****
  1222. @func error_status_t | s_ApiCreateResTypeEnum | Enumerates the list of
  1223. nodes in which the resource type can be supported and
  1224. returns the list of nodes to the caller. The client-side
  1225. is responsible for freeing the allocated memory.
  1226. @parm IN handle_t | IDL_handle | RPC binding handle, not used.
  1227. @parm IN LPCWSTR | lpszTypeName | Name of the resource type.
  1228. @parm IN DWORD | dwType | Supplies the type of properties
  1229. to be enumerated.
  1230. @parm OUT PNM_NODE | ReturnEnum | Returns the requested objects.
  1231. @comm This routine helps enumerating all the nodes that a particular
  1232. resource type can be supported on.
  1233. @rdesc ERROR_SUCCESS on success. Win32 error code otherwise.
  1234. @xref
  1235. ****/
  1236. error_status_t
  1237. s_ApiCreateResTypeEnum(
  1238. IN handle_t IDL_handle,
  1239. IN LPCWSTR lpszTypeName,
  1240. IN DWORD dwType,
  1241. OUT PENUM_LIST *ReturnEnum
  1242. )
  1243. {
  1244. DWORD Status;
  1245. DWORD Allocated = 0;
  1246. PENUM_LIST Enum = NULL;
  1247. DWORD i;
  1248. DWORD Result;
  1249. PFM_RESTYPE pResType = NULL;
  1250. PNM_NODE pNode;
  1251. LPWSTR RealName = NULL;
  1252. pResType = OmReferenceObjectById(ObjectTypeResType,
  1253. lpszTypeName);
  1254. if (dwType & ~CLUSTER_RESOURCE_TYPE_ENUM_ALL) {
  1255. Status = ERROR_INVALID_PARAMETER;
  1256. goto ErrorExit;
  1257. }
  1258. Allocated = INITIAL_ENUM_LIST_ALLOCATION;
  1259. Enum = MIDL_user_allocate(ENUM_SIZE(Allocated));
  1260. if (Enum == NULL) {
  1261. Status = ERROR_NOT_ENOUGH_MEMORY;
  1262. goto ErrorExit;
  1263. }
  1264. if (pResType == NULL) {
  1265. //
  1266. // The object cannot be found in the list !
  1267. //
  1268. Status = ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND;
  1269. goto ErrorExit;
  1270. }
  1271. Enum->EntryCount = 0;
  1272. //
  1273. // Enumerate all possible nodes
  1274. //
  1275. if (dwType & CLUSTER_RESOURCE_TYPE_ENUM_NODES) {
  1276. i=0;
  1277. do {
  1278. Result = FmEnumResourceTypeNode(pResType,
  1279. i,
  1280. &pNode);
  1281. if (Result == ERROR_SUCCESS) {
  1282. RealName = (LPWSTR)OmObjectName( pNode );
  1283. if (RealName != NULL) {
  1284. ApipAddToEnum(&Enum,
  1285. &Allocated,
  1286. RealName,
  1287. CLUSTER_RESOURCE_TYPE_ENUM_NODES);
  1288. }
  1289. OmDereferenceObject( pNode );
  1290. ++i;
  1291. }
  1292. } while ( Result == ERROR_SUCCESS );
  1293. }
  1294. *ReturnEnum = Enum;
  1295. OmDereferenceObject( pResType );
  1296. return(ERROR_SUCCESS);
  1297. ErrorExit:
  1298. if (pResType != NULL) {
  1299. OmDereferenceObject( pResType );
  1300. }
  1301. if (Enum != NULL) {
  1302. MIDL_user_free(Enum);
  1303. }
  1304. *ReturnEnum = NULL;
  1305. return(Status);
  1306. }