diff --git a/OpenStackManager.php b/OpenStackManager.php index e22a194..60ff338 100644 --- a/OpenStackManager.php +++ b/OpenStackManager.php @@ -1,465 +1,453 @@ * @copyright © 2010 Ryan Lane * @license GNU General Public Licence 2.0 or later */ if ( !defined( 'MEDIAWIKI' ) ) { echo( "This file is an extension to the MediaWiki software and cannot be used standalone.\n" ); die( 1 ); } $wgExtensionCredits['other'][] = array( 'path' => __FILE__, 'name' => 'OpenStackManager', 'author' => 'Ryan Lane', 'version' => '2.2.0', 'url' => 'http://mediawiki.org/wiki/Extension:OpenStackManager', 'descriptionmsg' => 'openstackmanager-desc', 'license-name' => 'GPL-2.0+', ); define( 'CONTENT_MODEL_YAML', 'yaml' ); define( 'CONTENT_FORMAT_YAML', 'application/yaml' ); define( "NS_NOVA_RESOURCE", 498 ); define( "NS_NOVA_RESOURCE_TALK", 499 ); define( 'NS_HIERA', 666 ); define( 'NS_HIERA_TALK', 667 ); $wgExtraNamespaces[NS_HIERA] = 'Hiera'; $wgExtraNamespaces[NS_HIERA_TALK] = 'Hiera_Talk'; $wgContentHandlers[CONTENT_MODEL_YAML] = 'YamlContentHandler'; $wgNamespaceContentModels[NS_HIERA] = CONTENT_MODEL_YAML; $wgSyntaxHighlightModels[CONTENT_MODEL_YAML] = 'yaml'; $wgExtraNamespaces[NS_NOVA_RESOURCE] = 'Nova_Resource'; $wgExtraNamespaces[NS_NOVA_RESOURCE_TALK] = 'Nova_Resource_Talk'; $wgContentNamespaces[] = NS_NOVA_RESOURCE; $wgAvailableRights[] = 'listall'; $wgAvailableRights[] = 'manageproject'; $wgAvailableRights[] = 'managednsdomain'; $wgAvailableRights[] = 'manageglobalpuppet'; $wgAvailableRights[] = 'loginviashell'; $wgAvailableRights[] = 'accessrestrictedregions'; $wgAvailableRights[] = 'editallhiera'; $wgHooks['UserAddGroup'][] = 'OpenStackNovaUser::addUserToBastionProject'; $wgHooks['UserRemoveGroup'][] = 'OpenStackNovaUser::removeUserFromBastionProject'; $wgHooks['getUserPermissionsErrors'][] = 'OpenStackManagerHooks::getUserPermissionsErrors'; -# Block runs on Wikimedia Jenkins CI system -if ( isset( $wgWikimediaJenkinsCI ) && $wgWikimediaJenkinsCI ) { - - # Please MediaWiki ApiDocumentationTest which invokes our API calls which - # require $wgAuth to be an instance of the LdapAuthenticationPlugin. - # T124613 - $wgExtensionFunctions[] = function () { - global $wgAuth; - $wgAuth = new LdapAuthenticationPlugin(); - }; -} - // Keystone identity URI $wgOpenStackManagerNovaIdentityURI = 'http://localhost:5000/v2.0'; $wgOpenStackManagerNovaIdentityV3URI = 'http://localhost:5000/v3'; // SSH key storage location, ldap or nova $wgOpenStackManagerNovaKeypairStorage = 'ldap'; // LDAP Auth domain used for OSM $wgOpenStackManagerLDAPDomain = ''; // UserDN used for reading and writing on the LDAP database $wgOpenStackManagerLDAPUser = ''; // Actual username of the LDAP user $wgOpenStackManagerLDAPUsername = ''; // Password used to bind $wgOpenStackManagerLDAPUserPassword = ''; // Project that $wgOpenStackManagerLDAPUsername has admin on $wgOpenStackManagerProject = ''; // Keystone ID of same $wgOpenStackManagerProjectId = ''; // DN location of projects $wgOpenStackManagerLDAPProjectBaseDN = ''; // DN location of hosts/instances $wgOpenStackManagerLDAPProjectBaseDN = ''; // DN location of service groups $wgOpenStackManagerLDAPServiceGroupBaseDN = ''; // Service groups will be automatically prefaced with this; // e.g. if the user asks for 'fancytool' the group will be called // 'local-fancytool'. $wgOpenStackManagerServiceGroupPrefix = 'local-'; // Default pattern for service group homedir creation. // %u is username, %p is $wgOpenStackManagerServiceGroupPrefix. $wgOpenStackManagerServiceGroupHomedirPattern = '/home/%p%u/'; // Key/value pairs like array( 'region1' => '10.4.0.11', 'region2' => '10.68.1.35' ) $wgOpenStackManagerProxyGateways = array(); $wgOpenStackManagerIdRanges = array( 'service' => array( 'gid' => array( 'min' => 40000, 'max' => 49999 ), ), ); // DN location for posix groups based on projects $wgOpenStackManagerLDAPProjectGroupBaseDN = ""; $wgOpenStackManagerLDAPDefaultGid = '500'; // Shell used when creating users $wgOpenStackManagerLDAPDefaultShell = '/bin/bash'; // DNS servers, used in SOA record $wgOpenStackManagerDNSServers = array( 'primary' => 'localhost', 'secondary' => 'localhost' ); // SOA attributes $wgOpenStackManagerDNSSOA = array( 'hostmaster' => 'hostmaster@localhost.localdomain', 'refresh' => '1800', 'retry' => '3600', 'expiry' => '86400', 'minimum' => '7200' ); // Default classes and variables to apply to instances when created $wgOpenStackManagerPuppetOptions = array( 'enabled' => false, 'defaultclasses' => array(), 'defaultvariables' => array() ); // User data to inject into instances when created $wgOpenStackManagerInstanceUserData = array( 'cloud-config' => array(), 'scripts' => array(), 'upstarts' => array(), ); // Default security rules to add to a project when created $wgOpenStackManagerDefaultSecurityGroupRules = array(); // List of instance type names to not display on instance creation interface $wgOpenStackManagerInstanceBannedInstanceTypes = array(); // Whether resource pages should be managed on instance/project creation/deletion $wgOpenStackManagerCreateResourcePages = true; // Whether a Server Admin Log page should be created with project pages $wgOpenStackManagerCreateProjectSALPages = true; // Whether we should remove a user from all projects on removal of loginviashell $wgOpenStackManagerRemoveUserFromAllProjectsOnShellDisable = true; // Whether we should remove a user from bastion on removal of loginviashell $wgOpenStackManagerRemoveUserFromBastionProjectOnShellDisable = false; // 'bastion' project name $wgOpenStackManagerBastionProjectName = 'bastion'; $wgOpenStackManagerBastionProjectId = 'bastion'; // Base URL for puppet docs. Classname will be appended with s/::/\//g $wgOpenStackManagerPuppetDocBase = ''; /** * Path to the ssh-keygen utility. Used for converting ssh key formats. False to disable its use. */ $wgSshKeygen = 'ssh-keygen'; /** * Path to the puttygen utility. Used for converting ssh key formats. False to disable its use. */ $wgPuttygen = 'puttygen'; // Custom namespace for projects $wgOpenStackManagerProjectNamespace = NS_NOVA_RESOURCE; // A list of regions restricted to a group by right $wgOpenStackManagerRestrictedRegions = array(); // A list of regions which are visible yet disabled (e.g. instance creation forbidden) $wgOpenStackManagerReadOnlyRegions = array(); $dir = __DIR__ . '/'; $wgMessagesDirs['OpenStackManager'] = __DIR__ . '/i18n'; $wgExtensionMessagesFiles['OpenStackManager'] = $dir . 'OpenStackManager.i18n.php'; $wgExtensionMessagesFiles['OpenStackManagerAlias'] = $dir . 'OpenStackManager.alias.php'; $wgAutoloadClasses['YamlContent'] = $dir . 'includes/YamlContent.php'; $wgAutoloadClasses['YamlContentHandler'] = $dir . 'includes/YamlContentHandler.php'; $wgAutoloadClasses['OpenStackManagerHooks'] = $dir . 'OpenStackManagerHooks.php'; $wgAutoloadClasses['OpenStackNovaInstance'] = $dir . 'nova/OpenStackNovaInstance.php'; $wgAutoloadClasses['OpenStackNovaInstanceType'] = $dir . 'nova/OpenStackNovaInstanceType.php'; $wgAutoloadClasses['OpenStackNovaImage'] = $dir . 'nova/OpenStackNovaImage.php'; $wgAutoloadClasses['OpenStackNovaKeypair'] = $dir . 'nova/OpenStackNovaKeypair.php'; $wgAutoloadClasses['OpenStackNovaController'] = $dir . 'nova/OpenStackNovaController.php'; $wgAutoloadClasses['OpenStackNovaUser'] = $dir . 'nova/OpenStackNovaUser.php'; $wgAutoloadClasses['OpenStackNovaDomain'] = $dir . 'nova/OpenStackNovaDomain.php'; $wgAutoloadClasses['OpenStackNovaHost'] = $dir . 'nova/OpenStackNovaHost.php'; $wgAutoloadClasses['OpenStackNovaPublicHost'] = $dir . 'nova/OpenStackNovaPublicHost.php'; $wgAutoloadClasses['OpenStackNovaPrivateHost'] = $dir . 'nova/OpenStackNovaPrivateHost.php'; $wgAutoloadClasses['OpenStackNovaAddress'] = $dir . 'nova/OpenStackNovaAddress.php'; $wgAutoloadClasses['OpenStackNovaSecurityGroup'] = $dir . 'nova/OpenStackNovaSecurityGroup.php'; $wgAutoloadClasses['OpenStackNovaSecurityGroupRule'] = $dir . 'nova/OpenStackNovaSecurityGroupRule.php'; $wgAutoloadClasses['OpenStackNovaRole'] = $dir . 'nova/OpenStackNovaRole.php'; $wgAutoloadClasses['OpenStackNovaServiceGroup'] = $dir . 'nova/OpenStackNovaServiceGroup.php'; $wgAutoloadClasses['OpenStackNovaVolume'] = $dir . 'nova/OpenStackNovaVolume.php'; $wgAutoloadClasses['OpenStackNovaSudoer'] = $dir . 'nova/OpenStackNovaSudoer.php'; $wgAutoloadClasses['OpenStackNovaProxy'] = $dir . 'nova/OpenStackNovaProxy.php'; $wgAutoloadClasses['OpenStackNovaArticle'] = $dir . 'nova/OpenStackNovaArticle.php'; $wgAutoloadClasses['OpenStackNovaPuppetGroup'] = $dir . 'nova/OpenStackNovaPuppetGroup.php'; $wgAutoloadClasses['OpenStackNovaLdapConnection'] = $dir . 'nova/OpenStackNovaLdapConnection.php'; $wgAutoloadClasses['OpenStackNovaProject'] = $dir . 'nova/OpenStackNovaProject.php'; $wgAutoloadClasses['OpenStackNovaProjectLimits'] = $dir . 'nova/OpenStackNovaProjectLimits.php'; $wgAutoloadClasses['OpenStackNovaProjectGroup'] = $dir . 'nova/OpenStackNovaProjectGroup.php'; $wgAutoloadClasses['SpecialNovaInstance'] = $dir . 'special/SpecialNovaInstance.php'; $wgAutoloadClasses['SpecialNovaKey'] = $dir . 'special/SpecialNovaKey.php'; $wgAutoloadClasses['SpecialNovaProject'] = $dir . 'special/SpecialNovaProject.php'; $wgAutoloadClasses['SpecialNovaDomain'] = $dir . 'special/SpecialNovaDomain.php'; $wgAutoloadClasses['SpecialNovaAddress'] = $dir . 'special/SpecialNovaAddress.php'; $wgAutoloadClasses['SpecialNovaSecurityGroup'] = $dir . 'special/SpecialNovaSecurityGroup.php'; $wgAutoloadClasses['SpecialNovaRole'] = $dir . 'special/SpecialNovaRole.php'; $wgAutoloadClasses['SpecialNovaServiceGroup'] = $dir . 'special/SpecialNovaServiceGroup.php'; $wgAutoloadClasses['SpecialNovaVolume'] = $dir . 'special/SpecialNovaVolume.php'; $wgAutoloadClasses['SpecialNovaSudoer'] = $dir . 'special/SpecialNovaSudoer.php'; $wgAutoloadClasses['SpecialNovaProxy'] = $dir . 'special/SpecialNovaProxy.php'; $wgAutoloadClasses['SpecialNovaPuppetGroup'] = $dir . 'special/SpecialNovaPuppetGroup.php'; $wgAutoloadClasses['SpecialNovaResources'] = $dir . 'special/SpecialNovaResources.php'; $wgAutoloadClasses['SpecialNova'] = $dir . 'special/SpecialNova.php'; $wgAutoloadClasses['ApiNovaInstance'] = $dir . 'api/ApiNovaInstance.php'; $wgAutoloadClasses['ApiNovaAddress'] = $dir . 'api/ApiNovaAddress.php'; $wgAutoloadClasses['ApiNovaProjects'] = $dir . 'api/ApiNovaProjects.php'; $wgAutoloadClasses['ApiNovaProjectLimits'] = $dir . 'api/ApiNovaProjectLimits.php'; $wgAutoloadClasses['ApiNovaServiceGroups'] = $dir . 'api/ApiNovaServiceGroups.php'; $wgAutoloadClasses['ApiListNovaProjects'] = $dir . 'api/ApiListNovaProjects.php'; $wgAutoloadClasses['ApiListNovaInstances'] = $dir . 'api/ApiListNovaInstances.php'; $wgAutoloadClasses['Spyc'] = $dir . 'Spyc.php'; $wgAutoloadClasses['OpenStackManagerNotificationFormatter'] = $dir . 'OpenStackManagerNotificationFormatter.php'; $wgAutoloadClasses['EchoOpenStackManagerPresentationModel'] = $dir . 'EchoOpenStackManagerPresentationModel.php'; $wgAutoloadClasses['OpenStackManagerEvent'] = $dir . 'OpenStackManagerEvent.php'; $wgSpecialPages['NovaInstance'] = 'SpecialNovaInstance'; $wgSpecialPages['NovaKey'] = 'SpecialNovaKey'; $wgSpecialPages['NovaProject'] = 'SpecialNovaProject'; $wgSpecialPages['NovaSecurityGroup'] = 'SpecialNovaSecurityGroup'; $wgSpecialPages['NovaServiceGroup'] = 'SpecialNovaServiceGroup'; $wgSpecialPages['NovaRole'] = 'SpecialNovaRole'; $wgSpecialPages['NovaVolume'] = 'SpecialNovaVolume'; $wgSpecialPages['NovaSudoer'] = 'SpecialNovaSudoer'; $wgSpecialPages['NovaPuppetGroup'] = 'SpecialNovaPuppetGroup'; $wgSpecialPages['NovaResources'] = 'SpecialNovaResources'; $wgHooks['LDAPSetCreationValues'][] = 'OpenStackNovaUser::LDAPSetCreationValues'; $wgHooks['LDAPRetrySetCreationValues'][] = 'OpenStackNovaUser::LDAPRetrySetCreationValues'; $wgHooks['LDAPModifyUITemplate'][] = 'OpenStackNovaUser::LDAPModifyUITemplate'; $wgHooks['AbortNewAccount'][] = 'OpenStackNovaUser::AbortNewAccount'; $wgHooks['LDAPUpdateUser'][] = 'OpenStackNovaUser::LDAPUpdateUser'; $wgHooks['DynamicSidebarGetGroups'][] = 'OpenStackNovaUser::DynamicSidebarGetGroups'; $wgHooks['ChainAuth'][] = 'OpenStackNovaUser::ChainAuth'; $wgHooks['GetPreferences'][] = 'OpenStackNovaUser::novaUserPreferences'; $commonModuleInfo = array( 'localBasePath' => __DIR__, 'remoteExtPath' => 'OpenStackManager', ); $wgResourceModules['ext.openstack'] = array( 'position' => 'top', 'styles' => 'modules/ext.openstack.css', 'dependencies' => array( 'jquery.spinner', 'mediawiki.api', 'jquery.ui.dialog', ), 'scripts' => array( 'modules/ext.openstack.js', ), ) + $commonModuleInfo; $wgResourceModules['ext.openstack.Instance'] = array( 'dependencies' => array( 'ext.openstack', ), 'messages' => array( 'openstackmanager-rebootinstancefailed', 'openstackmanager-rebootedinstance', 'openstackmanager-consoleoutput', 'openstackmanager-getconsoleoutputfailed', 'openstackmanager-deletedinstance', 'openstackmanager-deleteinstancefailed', 'openstackmanager-deleteinstance', 'openstackmanager-deleteinstancequestion', ), 'scripts' => array( 'modules/ext.openstack.Instance.js', ), ) + $commonModuleInfo; $wgResourceModules['ext.openstack.Address'] = array( 'dependencies' => array( 'ext.openstack', ), 'messages' => array( 'openstackmanager-disassociateaddressfailed', 'openstackmanager-disassociateaddress-confirm', 'openstackmanager-disassociatedaddress', 'openstackmanager-associateaddress', 'openstackmanager-releaseaddress', 'openstackmanager-unknownerror', ), 'scripts' => array( 'modules/ext.openstack.Address.js', ), ) + $commonModuleInfo; $wgAPIModules['novainstance'] = 'ApiNovaInstance'; $wgAPIModules['novaaddress'] = 'ApiNovaAddress'; $wgAPIModules['novaprojects'] = 'ApiNovaProjects'; $wgAPIModules['novaservicegroups'] = 'ApiNovaServiceGroups'; $wgAPIModules['novaprojectlimits'] = 'ApiNovaProjectLimits'; $wgAPIListModules['novaprojects'] = 'ApiListNovaProjects'; $wgAPIListModules['novainstances'] = 'ApiListNovaInstances'; # Schema changes $wgHooks['LoadExtensionSchemaUpdates'][] = 'efOpenStackSchemaUpdates'; /** * @param $updater DatabaseUpdater * @return bool */ function efOpenStackSchemaUpdates( $updater ) { $base = dirname( __FILE__ ); switch ( $updater->getDB()->getType() ) { case 'mysql': $updater->addExtensionTable( 'openstack_puppet_groups', "$base/openstack.sql" ); $updater->addExtensionTable( 'openstack_puppet_vars', "$base/openstack.sql" ); $updater->addExtensionTable( 'openstack_puppet_classes', "$base/openstack.sql" ); $updater->addExtensionTable( 'openstack_tokens', "$base/schema-changes/tokens.sql" ); $updater->addExtensionTable( 'openstack_notification_event', "$base/schema-changes/openstack_add_notification_events_table.sql" ); $updater->addExtensionUpdate( array( 'addField', 'openstack_puppet_groups', 'group_project', "$base/schema-changes/openstack_project_field.sql", true ) ); $updater->addExtensionUpdate( array( 'addField', 'openstack_puppet_groups', 'group_is_global', "$base/schema-changes/openstack_group_is_global_field.sql", true ) ); $updater->addExtensionUpdate( array( 'dropField', 'openstack_puppet_groups', 'group_position', "$base/schema-changes/openstack_drop_positions.sql", true ) ); $updater->addExtensionUpdate( array( 'dropField', 'openstack_puppet_vars', 'var_position', "$base/schema-changes/openstack_drop_positions.sql", true ) ); $updater->addExtensionUpdate( array( 'dropField', 'openstack_puppet_classes', 'class_position', "$base/schema-changes/openstack_drop_positions.sql", true ) ); $updater->addExtensionUpdate( array( 'addIndex', 'openstack_puppet_vars', 'var_name', "$base/schema-changes/openstack_add_name_indexes.sql", true ) ); $updater->addExtensionUpdate( array( 'addIndex', 'openstack_puppet_vars', 'var_group_id', "$base/schema-changes/openstack_add_name_indexes.sql", true ) ); $updater->addExtensionUpdate( array( 'addIndex', 'openstack_puppet_classes', 'class_name', "$base/schema-changes/openstack_add_name_indexes.sql", true ) ); $updater->addExtensionUpdate( array( 'addIndex', 'openstack_puppet_classes', 'class_group_id', "$base/schema-changes/openstack_add_name_indexes.sql", true ) ); $updater->addExtensionUpdate( array( 'modifyField', 'openstack_tokens', 'token', "$base/schema-changes/openstack_change_token_size.sql", true ) ); break; } return true; } # Echo integration $wgHooks['BeforeCreateEchoEvent'][] = 'efOpenStackOnBeforeCreateEchoEvent'; $wgHooks['EchoGetDefaultNotifiedUsers'][] = 'efOpenStackGetDefaultNotifiedUsers'; $wgDefaultUserOptions['echo-subscriptions-web-osm-instance-build-completed'] = true; $wgDefaultUserOptions['echo-subscriptions-email-osm-instance-build-completed'] = true; $wgDefaultUserOptions['echo-subscriptions-web-osm-instance-reboot-completed'] = true; $wgDefaultUserOptions['echo-subscriptions-web-osm-instance-deleted'] = true; $wgDefaultUserOptions['echo-subscriptions-email-osm-instance-deleted'] = true; $wgDefaultUserOptions['echo-subscriptions-web-osm-projectmembers-add'] = true; $wgDefaultUserOptions['echo-subscriptions-email-osm-projectmembers-add'] = true; /** * Add OSM events to Echo. * * @param array $notifications Echo notifications * @param array $notificationCategories Echo notification categories */ function efOpenStackOnBeforeCreateEchoEvent( &$notifications, &$notificationCategories ) { $notifications['osm-instance-build-completed'] = array( 'formatter-class' => 'OpenStackManagerNotificationFormatter', 'presentation-model' => 'EchoOpenStackManagerPresentationModel', 'category' => 'osm-instance-build-completed', 'icon' => 'placeholder', 'payload' => array( 'summary' ), 'email-subject-message' => 'notification-osm-instance-build-completed-email-subject', 'email-subject-params' => array( 'instance' ), 'email-body-batch-message' => 'notification-osm-instance-build-completed-email-body-batch', 'email-body-batch-params' => array( 'agent', 'title', 'instance' ), ); $notifications['osm-instance-reboot-completed'] = array( 'formatter-class' => 'OpenStackManagerNotificationFormatter', 'presentation-model' => 'EchoOpenStackManagerPresentationModel', 'category' => 'osm-instance-reboot-completed', 'icon' => 'placeholder', 'payload' => array( 'summary' ), 'email-subject-message' => 'notification-osm-instance-reboot-completed-email-subject', 'email-subject-params' => array( 'instance' ), 'email-body-batch-message' => 'notification-osm-instance-reboot-completed-email-body-batch', 'email-body-batch-params' => array( 'agent', 'title', 'instance' ), ); $notifications['osm-instance-deleted'] = array( 'formatter-class' => 'OpenStackManagerNotificationFormatter', 'presentation-model' => 'EchoOpenStackManagerPresentationModel', 'category' => 'osm-instance-deleted', 'icon' => 'trash', 'payload' => array( 'summary' ), 'email-subject-message' => 'notification-osm-instance-deleted-email-subject', 'email-subject-params' => array( 'instance' ), 'email-body-batch-message' => 'notification-osm-instance-deleted-email-body-batch', 'email-body-batch-params' => array( 'agent', 'title', 'instance' ), ); $notifications['osm-projectmembers-add'] = array( 'formatter-class' => 'OpenStackManagerNotificationFormatter', 'presentation-model' => 'EchoOpenStackManagerPresentationModel', 'category' => 'osm-projectmembers-add', 'icon' => 'placeholder', 'payload' => array( 'summary' ), 'email-subject-message' => 'notification-osm-projectmember-added-email-subject', 'email-subject-params' => array(), 'email-body-batch-message' => 'notification-osm-projectmember-added-email-body-batch', 'email-body-batch-params' => array( 'agent', 'title' ), ); return true; } /** * Define who gets notifications for an event. * * @param $event EchoEvent to get implicitly subscribed users for * @param &$users array to append implicitly subscribed users to. * @return bool true in all cases */ function efOpenStackGetDefaultNotifiedUsers ( $event, &$users ) { if ( $event->getType() == 'osm-instance-build-completed' || $event->getType() == 'osm-instance-deleted' ) { $extra = $event->getExtra(); foreach ( OpenStackNovaProject::getProjectByName( $extra['projectName'] )->getRoles() as $role ) { if ( $role->getRoleName() == 'projectadmin' ) { foreach ( $role->getMembers() as $roleMember ) { $roleMemberUser = User::newFromName( $roleMember ); $users[$roleMemberUser->getId()] = $roleMemberUser; } } } } elseif ( $event->getType() == 'osm-instance-reboot-completed' ) { // Only notify the person who initiated the reboot. $users[$event->getAgent()->getId()] = $event->getAgent(); } elseif ( $event->getType() == 'osm-projectmembers-add' ) { $extra = $event->getExtra(); $users[$extra['userAdded']] = User::newFromId( $extra['userAdded'] ); } unset( $users[0] ); return true; } $wgHooks['BeforePageDisplay'][] = 'efOpenStackBeforePageDisplay'; /** * @param $out OutputPage * @param $skin Skin * @return bool */ function efOpenStackBeforePageDisplay( $out, $skin ) { if ( $out->getTitle()->isSpecial( 'Preferences' ) ) { $out->addModuleStyles( 'ext.openstack' ); } return true; } diff --git a/maintenance/purgeOldServiceGroups.php b/maintenance/purgeOldServiceGroups.php index 65c7423..8423afe 100644 --- a/maintenance/purgeOldServiceGroups.php +++ b/maintenance/purgeOldServiceGroups.php @@ -1,123 +1,123 @@ mDescription = "Delete all service users and groups of the form n=local-,ou=groups,cn=,ou=projects,dc=wikimedia,dc=org"; } public function execute() { global $wgOpenStackManagerLDAPUsername; - global $wgAuth; + $ldap = LdapAuthenticationPlugin::getInstance(); $user = new OpenStackNovaUser( $wgOpenStackManagerLDAPUsername ); $projects = OpenStackNovaProject::getAllProjects(); $failedSync = false; $attempt_count = 0; $synced_count = 0; $failed_count = 0; /** * @var $project OpenStackNovaProject */ foreach ( $projects as $project ) { // actually load the project info from ldap // (getAllProjects() doesn't do this) $project->fetchProjectInfo(); $projectName = $project->getProjectName(); $oldServiceGroupOUDN = 'ou=groups,' . $project->getProjectDN(); $oldServiceUserOUDN = 'ou=people,' . $project->getProjectDN(); - $result = LdapAuthenticationPlugin::ldap_search( $wgAuth->ldapconn, + $result = LdapAuthenticationPlugin::ldap_search( $ldap->ldapconn, $oldServiceGroupOUDN, '(objectclass=groupofnames)' ); if ( $result ) { $this->serviceGroups = array(); - $groupList = LdapAuthenticationPlugin::ldap_get_entries( $wgAuth->ldapconn, $result ); + $groupList = LdapAuthenticationPlugin::ldap_get_entries( $ldap->ldapconn, $result ); if ( isset( $groupList ) ) { array_shift( $groupList ); foreach ( $groupList as $groupEntry ) { $deleteme = "cn=" . $groupEntry['cn'][0] . "," . $oldServiceGroupOUDN; print "needs deleting: " . $deleteme . "..."; $attempt_count++; - $success = LdapAuthenticationPlugin::ldap_delete( $wgAuth->ldapconn, $deleteme ); + $success = LdapAuthenticationPlugin::ldap_delete( $ldap->ldapconn, $deleteme ); if ( $success ) { $synced_count++; print( "done.\n"); } else { $failed_count++; print( "FAILED\n"); } } } } - $result = LdapAuthenticationPlugin::ldap_search( $wgAuth->ldapconn, + $result = LdapAuthenticationPlugin::ldap_search( $ldap->ldapconn, $oldServiceUserOUDN, '(objectclass=person)' ); if ( $result ) { $this->serviceGroups = array(); - $groupList = LdapAuthenticationPlugin::ldap_get_entries( $wgAuth->ldapconn, $result ); + $groupList = LdapAuthenticationPlugin::ldap_get_entries( $ldap->ldapconn, $result ); if ( isset( $groupList ) ) { array_shift( $groupList ); foreach ( $groupList as $groupEntry ) { $deleteme = "uid=" . $groupEntry['cn'][0] . "," . $oldServiceUserOUDN; print "user needs deleting: " . $deleteme . "..."; $attempt_count++; - $success = LdapAuthenticationPlugin::ldap_delete( $wgAuth->ldapconn, $deleteme ); + $success = LdapAuthenticationPlugin::ldap_delete( $ldap->ldapconn, $deleteme ); if ( $success ) { $synced_count++; print( "done.\n"); } else { $failed_count++; print( "FAILED\n"); } } } } $deleteme = $oldServiceGroupOUDN; print "ou needs deleting: " . $deleteme . "..."; $attempt_count++; - $success = LdapAuthenticationPlugin::ldap_delete( $wgAuth->ldapconn, $deleteme ); + $success = LdapAuthenticationPlugin::ldap_delete( $ldap->ldapconn, $deleteme ); if ( $success ) { $synced_count++; print( "done.\n"); } else { $failed_count++; print( "FAILED\n"); } $deleteme = $oldServiceUserOUDN; print "ou needs deleting: " . $deleteme . "..."; $attempt_count++; - $success = LdapAuthenticationPlugin::ldap_delete( $wgAuth->ldapconn, $deleteme ); + $success = LdapAuthenticationPlugin::ldap_delete( $ldap->ldapconn, $deleteme ); if ( $success ) { $synced_count++; print( "done.\n"); } else { $failed_count++; print( "FAILED\n"); } } $this->output( "$attempt_count items needed cleanup. $synced_count removed, $failed_count failed.\n" ); $this->output( "Done.\n" ); return ($failed_count == 0); } } $maintClass = "OpenStackNovaPurgeOldServiceGroups"; require_once( RUN_MAINTENANCE_IF_MAIN ); diff --git a/maintenance/qualifyInstancePages.php b/maintenance/qualifyInstancePages.php index 923cf1e..3c5b819 100644 --- a/maintenance/qualifyInstancePages.php +++ b/maintenance/qualifyInstancePages.php @@ -1,61 +1,61 @@ mDescription = "Move instance pages from id to fqdn."; } public function execute() { - global $wgAuth; global $wgOpenStackManagerLDAPUsername; global $wgOpenStackManagerLDAPUserPassword; $user = new OpenStackNovaUser( $wgOpenStackManagerLDAPUsername ); $userNova = OpenStackNovaController::newFromUser( $user ); $projects = OpenStackNovaProject::getAllProjects(); # HACK (please fix): Keystone doesn't deliver services and endpoints unless # a project token is returned, so we need to feed it a project. Ideally this # should be configurable, and not hardcoded like this. $userNova->setProject( 'bastion' ); $userNova->authenticate( $wgOpenStackManagerLDAPUsername, $wgOpenStackManagerLDAPUserPassword ); $regions = $userNova->getRegions( 'compute' ); foreach ( $regions as $region ) { $this->output( "Running region: " . $region . "\n" ); foreach ( $projects as $project ) { $projectName = $project->getProjectName(); $this->output( "Running project: " . $projectName . "\n" ); $userNova->setProject( $projectName ); $userNova->setRegion( $region ); $instances = $userNova->getInstances(); if ( ! $instances ) { - $wgAuth->printDebug( "No instance, continuing", NONSENSITIVE ); + $ldap = LdapAuthenticationPlugin::getInstance(); + $ldap->printDebug( "No instance, continuing", NONSENSITIVE ); continue; } foreach ( $instances as $instance ) { $host = $instance->getHost(); if ( !$host ) { $this->output( "Skipping instance due to missing host entry: " . $instance->getInstanceId() . "\n" ); continue; } $this->output( "Renaming instance: " . $instance->getInstanceId() . "\n" ); $ot = Title::newFromText( $instance->getInstanceId(), NS_NOVA_RESOURCE ); $nt = Title::newFromText( $host->getFullyQualifiedHostName(), NS_NOVA_RESOURCE ); $ot->moveTo( $nt, false, 'Maintenance script move from id to fqdn.' ); } } } $this->output( "Done.\n" ); } } $maintClass = "OpenStackNovaQualifyInstancePages"; require_once( RUN_MAINTENANCE_IF_MAIN ); diff --git a/maintenance/updateInstancePages.php b/maintenance/updateInstancePages.php index 7ff65b8..f4151d2 100644 --- a/maintenance/updateInstancePages.php +++ b/maintenance/updateInstancePages.php @@ -1,54 +1,54 @@ mDescription = "Update all instance pages in the wiki"; } public function execute() { - global $wgAuth; global $wgOpenStackManagerLDAPUsername; global $wgOpenStackManagerLDAPUserPassword; $user = new OpenStackNovaUser( $wgOpenStackManagerLDAPUsername ); $userNova = OpenStackNovaController::newFromUser( $user ); $projects = OpenStackNovaProject::getAllProjects(); # HACK (please fix): Keystone doesn't deliver services and endpoints unless # a project token is returned, so we need to feed it a project. Ideally this # should be configurable, and not hardcoded like this. $userNova->setProject( 'bastion' ); $userNova->authenticate( $wgOpenStackManagerLDAPUsername, $wgOpenStackManagerLDAPUserPassword ); $regions = $userNova->getRegions( 'compute' ); foreach ( $regions as $region ) { $this->output( "Running region : " . $region . "\n" ); foreach ( $projects as $project ) { $projectName = $project->getProjectName(); $this->output( "Running project : " . $projectName . "\n" ); $userNova->setProject( $projectName ); $userNova->setRegion( $region ); $instances = $userNova->getInstances(); if ( ! $instances ) { - $wgAuth->printDebug( "No instance, continuing", NONSENSITIVE ); + $ldap = LdapAuthenticationPlugin::getInstance(); + $ldap->printDebug( "No instance, continuing", NONSENSITIVE ); continue; } foreach ( $instances as $instance ) { $this->output( "Updating instance : " . $instance->getInstanceId() . "\n" ); $instance->editArticle( $userNova ); } } } $this->output( "Done.\n" ); } } $maintClass = "OpenStackNovaUpdateInstancePages"; require_once( RUN_MAINTENANCE_IF_MAIN ); diff --git a/maintenance/updatedomains.php b/maintenance/updatedomains.php index 8862ea7..72c19fc 100644 --- a/maintenance/updatedomains.php +++ b/maintenance/updatedomains.php @@ -1,105 +1,104 @@ addOption( 'name', 'The instance hostname, e.g. bastion1', false, true ); $this->addOption( 'project', 'The instance project name, e.g. bastion', false, true ); $this->addOption( 'region', 'The instance region, e.g. eqiad', false, true ); $this->addOption( 'all-instances', 'Run this command on every instance.', false, false ); } public function execute() { - global $wgAuth; global $wgOpenStackManagerLDAPUsername; global $wgOpenStackManagerLDAPUserPassword; if ( $this->hasOption( 'all-instances' ) ) { if ( $this->hasOption( 'region' ) ) { $this->error( "--all-instances cannot be used with --region.\n", true ); } $instancelist = array(); $user = new OpenStackNovaUser( $wgOpenStackManagerLDAPUsername ); $userNova = OpenStackNovaController::newFromUser( $user ); $projects = OpenStackNovaProject::getAllProjects(); $userNova->setProject( 'bastion' ); $userNova->authenticate( $wgOpenStackManagerLDAPUsername, $wgOpenStackManagerLDAPUserPassword ); $regions = $userNova->getRegions( 'compute' ); foreach ( $regions as $region ) { foreach ( $projects as $project ) { $projectName = $project->getProjectName(); $userNova->setProject( $projectName ); $userNova->setRegion( $region ); $instances = $userNova->getInstances(); if ( $instances ) { foreach ( $instances as $instance ) { $instancelist[] = array( $region, $instance->getInstanceName(), $projectName ); } } } } } elseif ( $this->hasOption( 'name' ) ) { if ( ! $this->hasOption( 'region' ) ) { $this->error( "--name requires --region.\n", true ); } if ( ! $this->hasOption( 'project' ) ) { $this->error( "--name requires --project.\n", true ); } $instancelist = array( array( $this->getOption( 'region' ), $this->getOption( 'name' ), $this->getOption( 'project' ), ) ); } else { $this->error( "Must specify either --name or --all-instances.\n", true ); } if ( !class_exists( 'OpenStackNovaHost' ) ) { $this->error( "Couldn't find OpenStackNovaHost class.\n", true ); } OpenStackNovaLdapConnection::connect(); foreach ( $instancelist as $instancepair ) { list( $instanceregion, $instancename, $instanceproject ) = $instancepair; $host = OpenStackNovaHost::getHostByNameAndProject( $instancename, $instanceproject, $instanceregion ); if ( ! $host ) { print "Skipping $instancename.$instanceproject.$instanceregion; not found.\n"; continue; } print "\nFor instance $instancename in region $instanceregion and project $instanceproject:\n\n"; $namefqdn = $instancename . '.' . $instanceproject . '.' . $instanceregion . '.' . 'wmflabs'; $host->addAssociatedDomain($namefqdn); } } } $maintClass = "UpdateDomains"; require_once( RUN_MAINTENANCE_IF_MAIN ); diff --git a/nova/OpenStackNovaController.php b/nova/OpenStackNovaController.php index 722c5ee..38a0c77 100644 --- a/nova/OpenStackNovaController.php +++ b/nova/OpenStackNovaController.php @@ -1,1158 +1,1158 @@ project = ''; $this->token = ''; $this->username = $user->getUsername(); $this->user = $user; } /** * @param $user string * @return OpenStackNovaController */ static function newFromUser( $user ) { return new OpenStackNovaController( $user ); } /** * Get a mime representation of a file with the specified attachmenttext. * No parameters are escaped in this function. This function should never be * called when dealing with end-user provided data. * * @param $attachmenttext * @param $mimetype * @param $filename * * @return string */ function getAttachmentMime( $attachmenttext, $mimetype, $filename ) { $endl = $this->getLineEnding(); $attachment = 'Content-Type: ' . $mimetype . '; charset="us-ascii"'. $endl; $attachment .= 'MIME-Version: 1.0' . $endl; $attachment .= 'Content-Transfer-Encoding: 7bit' . $endl; $attachment .= 'Content-Disposition: attachment; filename="' . $filename . '"' . $endl; $attachment .= $endl; $attachment .= $attachmenttext; return $attachment; } function getLineEnding() { if ( wfIsWindows() ) { return "\r\n"; } else { return "\n"; } } function getProject() { return $this->project; } function setProject( $project ) { $this->project = $project; } function getRegion() { return $this->region; } function getRegions( $service ) { global $wgMemc; global $wgUser; global $wgOpenStackManagerRestrictedRegions; // We need to ensure the project token has been // fetched before we can get the regions. $this->getProjectToken( $this->project ); $key = wfMemcKey( 'openstackmanager', 'serviceCatalog-' . $this->project, $this->username ); $serviceCatalog = json_decode( $wgMemc->get( $key ) ); $regions = array(); if ( $serviceCatalog ) { foreach ( $serviceCatalog as $entry ) { if ( $entry->type === "identity" ) { foreach ( $entry->endpoints as $endpoint ) { if ( !$wgUser->isAllowed( 'accessrestrictedregions' ) && in_array( $endpoint->region, $wgOpenStackManagerRestrictedRegions ) ) { continue; } $regions[] = $endpoint->region; } } } } return array_unique( $regions ); } function setRegion( $region ) { $this->region = $region; } /** * @param $id * @return null */ function getAddress( $id ) { $id = urlencode( $id ); $ret = $this->restCall( 'compute', '/os-floating-ips/' . $id, 'GET' ); $address = self::_get_property( $ret['body'], 'floating_ip' ); if ( $address ) { return new OpenStackNovaAddress( $address ); } else { return null; } } /** * @return array */ function getAddresses() { $addressesarr = array(); $ret = $this->restCall( 'compute', '/os-floating-ips', 'GET' ); $addresses = self::_get_property( $ret['body'], 'floating_ips' ); if ( !$addresses ) { return $addressesarr; } foreach ( $addresses as $address ) { $address = new OpenStackNovaAddress( $address ); $ip = $address->getPublicIp(); $addressesarr[$ip] = $address; } return $addressesarr; } /** * @param $instanceId * @return null|OpenStackNovaInstance */ function getInstance( $instanceId ) { $instanceId = urlencode( $instanceId ); $ret = $this->restCall( 'compute', '/servers/' . $instanceId, 'GET' ); if ( $ret['code'] === 200 ) { $server = self::_get_property( $ret['body'], 'server' ); if ( $server ) { return new OpenStackNovaInstance( $server, $this->getRegion(), true ); } } return null; } function createProxy( $fqdn, $backendHost, $backendPort ) { $data = array( 'domain' => $fqdn, 'backends' => array ( 'http://' . $backendHost . ':' . $backendPort ) ); $ret = $this->restCall( 'proxy', '/mapping', 'PUT', $data ); if ( $ret['code'] !== 200 ) { return null; } $proxyObj = new OpenStackNovaProxy( $this->project, $fqdn, $backendHost, $backendPort ); return $proxyObj; } function deleteProxy( $fqdn ) { $ret = $this->restCall( 'proxy', '/mapping/' . $fqdn, 'DELETE' ); if ( $ret['code'] !== 200 ) { return false; } return true; } /** * @return array */ function getProxiesForProject() { - global $wgAuth; - + $ldap = LdapAuthenticationPlugin::getInstance(); $proxyarr = array(); $ret = $this->restCall( 'proxy', '/mapping', 'GET' ); $proxies = self::_get_property( $ret['body'], 'routes' ); if ( !$proxies ) { return $proxyarr; } foreach ( $proxies as $proxy ) { $domain = self::_get_property( $proxy, 'domain' ); $backends = self::_get_property( $proxy, 'backends' ); if ( (count( $backends ) ) > 1 ) { - $wgAuth->printDebug( "Warning! proxy $domain has multiple backends but we only support one backend per proxy.", NONSENSITIVE ); + $ldap->printDebug( "Warning! proxy $domain has multiple backends but we only support one backend per proxy.", NONSENSITIVE ); } $backend = $backends[0]; $backendarray = explode( ':', $backends[0] ); if ( strpos( $backend, "http" ) === 0 ) { if ( ( count( $backendarray ) < 2 ) or ( count( $backendarray ) > 3 ) ) { - $wgAuth->printDebug( "Unable to parse backend $backend, discarding.", NONSENSITIVE ); + $ldap->printDebug( "Unable to parse backend $backend, discarding.", NONSENSITIVE ); } elseif ( count( $backendarray ) == 2 ) { $backendHost = $backend; $backendPort = null; } else { $backendHost = $backendarray[0] . ":" . $backendarray[1]; $backendPort = $backendarray[2]; } } else { if ( ( count( $backendarray ) < 1 ) or ( count( $backendarray ) > 2 ) ) { - $wgAuth->printDebug( "Unable to parse backend $backend, discarding.", NONSENSITIVE ); + $ldap->printDebug( "Unable to parse backend $backend, discarding.", NONSENSITIVE ); } elseif ( count( $backendarray ) == 1 ) { $backendHost = $backend; $backendPort = null; } else { $backendHost = $backendarray[0]; $backendPort = $backendarray[1]; } } if ( $backendPort ) { $proxyObj = new OpenStackNovaProxy( $this->project, $domain, $backendHost, $backendPort ); } else { $proxyObj = new OpenStackNovaProxy( $this->project, $domain, $backendHost ); } $proxyarr[] = $proxyObj; } return $proxyarr; } /** * @return a token for $wgOpenStackManagerLDAPUsername * who happens to have admin rights in Keystone. */ function _getAdminToken() { global $wgOpenStackManagerLDAPUsername, $wgOpenStackManagerLDAPUserPassword; - global $wgOpenStackManagerProjectId, $wgAuth; + global $wgOpenStackManagerProjectId; global $wgMemc; if ( $this->admintoken ) { return $this->admintoken; } $key = wfMemcKey( 'openstackmanager', 'keystoneadmintoken' ); $this->admintoken = $wgMemc->get( $key ); if ( is_string( $this->admintoken ) ) { return $this->admintoken; } $data = array( 'auth' => array( 'passwordCredentials' => array( 'username' => $wgOpenStackManagerLDAPUsername, 'password' => $wgOpenStackManagerLDAPUserPassword ), 'tenantId' => $wgOpenStackManagerProjectId ) ); $headers = array( 'Accept: application/json', 'Content-Type: application/json', ); $ret = $this->restCall( 'identity', '/tokens', 'POST', $data, $headers ); if ( $ret['code'] !== 200 ) { - $wgAuth->printDebug( "OpenStackNovaController::_getAdminToken return code: " . $ret['code'], NONSENSITIVE ); + $ldap = LdapAuthenticationPlugin::getInstance(); + $ldap->printDebug( "OpenStackNovaController::_getAdminToken return code: " . $ret['code'], NONSENSITIVE ); return ""; } $body = $ret['body']; $this->admintoken = self::_get_property( $body->access->token, 'id' ); $wgMemc->set( $key, $this->admintoken, 300 ); return $this->admintoken; } /** * @return array of project ids => project names */ function getProjects() { $admintoken = $this->_getAdminToken(); $headers = array( "X-Auth-Token: $admintoken" ); $projarr = array(); $ret = $this->restCall( 'identity', '/tenants', 'GET', array(), $headers ); $projects = self::_get_property( $ret['body'], 'tenants' ); if ( !$projects ) { return $projarr; } foreach ( $projects as $project ) { $projectname = self::_get_property( $project, 'name' ); $projectid = self::_get_property( $project, 'id' ); $projarr[$projectid] = $projectname; } return $projarr; } /** * @return string */ function getProjectName( $projectid ) { $admintoken = $this->_getAdminToken(); $headers = array( "X-Auth-Token: $admintoken" ); $userarr = array(); $ret = $this->restCall( 'identity', "/tenants/$projectid", 'GET', array(), $headers ); $tenant = self::_get_property( $ret['body'], 'tenant' ); return $tenant->name; } /** * @return id of new project or "" on failure */ function createProject( $projectname ) { $admintoken = $this->_getAdminToken(); $headers = array( 'Accept: application/json', 'Content-Type: application/json', "X-Auth-Token: $admintoken" ); $projname = urlencode( $projectname ); $data = array( 'tenant' => array( 'name' => $projname, 'id' => $projname ) ); $ret = $this->restCall( 'identity', '/tenants', 'POST', $data, $headers ); if ( $ret['code'] == 200 ) { $tenant = self::_get_property( $ret['body'], 'tenant' ); return self::_get_property( $tenant, 'id' ); } return ""; } function deleteProject( $projectid ) { $admintoken = $this->_getAdminToken(); $headers = array( "X-Auth-Token: $admintoken" ); $ret = $this->restCall( 'identity', "/tenants/$projectid", 'DELETE', array(), $headers ); if ( $ret['code'] !== 200 && $ret['code'] !== 204 ) { return false; } return true; } /** * @return array of user IDs => user names */ function getUsersInProject( $projectid ) { $admintoken = $this->_getAdminToken(); $headers = array( "X-Auth-Token: $admintoken" ); $userarr = array(); $ret = $this->restCall( 'identity', "/tenants/$projectid/users", 'GET', array(), $headers ); $users = self::_get_property( $ret['body'], 'users' ); if ( !$users ) { return $userarr; } foreach ( $users as $user ) { $name = self::_get_property( $user, 'name' ); $id = self::_get_property( $user, 'id' ); $userarr[$id] = $name; } return $userarr; } /** * @return array of $roleid => $rolename */ function getKeystoneRoles( ) { global $wgMemc; $key = wfMemcKey( 'openstackmanager', 'keystoneroles' ); $rolearr = $wgMemc->get( $key ); if ( is_array( $rolearr ) ) { return $rolearr; } $admintoken = $this->_getAdminToken(); $headers = array( "X-Auth-Token: $admintoken" ); $rolearr = array(); $ret = $this->restCall( 'identity', "/OS-KSADM/roles", 'GET', array(), $headers ); $roles = self::_get_property( $ret['body'], 'roles' ); if ( !$roles ) { return $rolearr; } foreach ( $roles as $role ) { $name = self::_get_property( $role, 'name' ); $id = self::_get_property( $role, 'id' ); $rolearr[$id] = $name; } $wgMemc->set( $key, $rolearr, 3600 ); return $rolearr; } /** * @return array of arrays: project ID => role IDs * * Return array only includes entries for projects * with roles assigned, so calling array_keys * on the return value will answer the question * 'what projects is this user in?' * */ function getRoleAssignmentsForUser( $userid ) { $admintoken = $this->_getAdminToken(); $headers = array( "X-Auth-Token: $admintoken" ); $assignments = array(); $ret = $this->restCall( 'identityv3', "/role_assignments?user.id=$userid", 'GET', array(), $headers ); $role_assignments = self::_get_property( $ret['body'], 'role_assignments' ); if ( !$role_assignments ) { return $projects; } foreach ( $role_assignments as $assignment ) { $scope = self::_get_property( $assignment, 'scope' ); $role = self::_get_property( $assignment, 'role' ); $roleid = self::_get_property( $role, 'id' ); $project = self::_get_property( $scope, 'project' ); $projectid = self::_get_property( $project, 'id' ); $assignments[$projectid][] = $roleid; } return $assignments; } /** * @return array of arrays: role ID => user IDs */ function getRoleAssignmentsForProject( $projectid ) { $admintoken = $this->_getAdminToken(); $headers = array( "X-Auth-Token: $admintoken" ); $assignments = array(); $ret = $this->restCall( 'identityv3', "/role_assignments?scope.project.id=$projectid", 'GET', array(), $headers ); $role_assignments = self::_get_property( $ret['body'], 'role_assignments' ); if ( !$role_assignments ) { return $assignments; } foreach ( $role_assignments as $assignment ) { $role = self::_get_property( $assignment, 'role' ); $roleid = self::_get_property( $role, 'id' ); $user = self::_get_property( $assignment, 'user' ); $userid = self::_get_property( $user, 'id' ); $assignments[$roleid][] = $userid; } return $assignments; } /** * @return array role IDs => role Names */ function getRolesForProjectAndUser( $projectid, $userid ) { $admintoken = $this->_getAdminToken(); $headers = array( "X-Auth-Token: $admintoken" ); $rolearr = array(); $ret = $this->restCall( 'identity', "/tenants/$projectid/users/$userid/roles", 'GET', array(), $headers ); $roles = self::_get_property( $ret['body'], 'roles' ); if ( !$roles ) { return $rolearr; } foreach ( $roles as $role ) { $id = self::_get_property( $role, 'id' ); $name = self::_get_property( $role, 'name' ); $rolearr[$id] = $name; } return $rolearr; } function grantRoleForProjectAndUser( $roleid, $projectid, $userid ) { $admintoken = $this->_getAdminToken(); $headers = array( 'Accept: application/json', 'Content-Type: application/json', "X-Auth-Token: $admintoken" ); $rolearr = array(); $ret = $this->restCall( 'identity', "/tenants/$projectid/users/$userid/roles/OS-KSADM/$roleid", 'PUT', array(), $headers ); if ( $ret['code'] !== 200 && $ret['code'] !== 201 ) { return false; } return true; } function revokeRoleForProjectAndUser( $roleid, $projectid, $userid ) { $admintoken = $this->_getAdminToken(); $headers = array( 'Accept: application/json', 'Content-Type: application/json', "X-Auth-Token: $admintoken" ); $rolearr = array(); $ret = $this->restCall( 'identity', "/tenants/$projectid/users/$userid/roles/OS-KSADM/$roleid", 'DELETE', array(), $headers ); if ( $ret['code'] !== 204 && $ret['code'] !== 200 ) { return false; } return true; } /** * @return OpenStackNovaInstance[] */ function getInstances() { $instancesarr = array(); $ret = $this->restCall( 'compute', '/servers/detail', 'GET' ); $instances = self::_get_property( $ret['body'], 'servers' ); if ( !$instances ) { return $instancesarr; } foreach ( $instances as $instance ) { $instance = new OpenStackNovaInstance( $instance, $this->getRegion(), true ); $id = $instance->getInstanceOSId(); $instancesarr[$id] = $instance; } return $instancesarr; } /** * @param $instancetypeid * @return OpenStackNovaInstanceType */ function getInstanceType( $instancetypeid ) { $instancetypeid = urlencode( $instancetypeid ); $ret = $this->restCall( 'compute', '/flavors/' . $instancetypeid, 'GET' ); $flavor = self::_get_property( $ret['body'], 'flavor' ); if ( $flavor ) { return new OpenStackNovaInstanceType( $flavor ); } return null; } /** * @return array */ function getInstanceTypes() { $ret = $this->restCall( 'compute', '/flavors/detail', 'GET' ); $instanceTypesarr = array(); $instanceTypes = self::_get_property( $ret['body'], 'flavors' ); if ( !$instanceTypes ) { return $instanceTypesarr; } foreach ( $instanceTypes as $instanceType ) { $instanceType = new OpenStackNovaInstanceType( $instanceType ); $instanceTypeName = $instanceType->getInstanceTypeName(); $instanceTypesarr[$instanceTypeName] = $instanceType; } OpenStackNovaInstanceType::sort( $instanceTypesarr ); return $instanceTypesarr; } /** * @param $imageid * @return null|\OpenStackNovaImage */ function getImage( $imageid ) { $imageid = urlencode( $imageid ); $ret = $this->restCall( 'compute', '/images/' . $imageid, 'GET' ); $image = self::_get_property( $ret['body'], 'image' ); if ( $image ) { return new OpenStackNovaImage( $image ); } return null; } /** * @return array */ function getImages() { $ret = $this->restCall( 'compute', '/images/detail', 'GET' ); $imagesarr = array(); $images = self::_get_property( $ret['body'], 'images' ); if ( !$images ) { return $imagesarr; } foreach ( $images as $image ) { $image = new OpenStackNovaImage( $image ); $imageId = $image->getImageId(); $imagesarr[$imageId] = $image; } return $imagesarr; } /** */ function getKeypairs() { // Currently unimplemented } /** * @param $groupid * @return OpenStackNovaSecurityGroup */ function getSecurityGroup( $groupid ) { // The API annoyingly doesn't allow you to pull a single group // pull them all, then return a single entry. $groups = $this->getSecurityGroups(); if ( isset( $groups[$groupid] ) ) { return $groups[$groupid]; } else { return null; } } /** * @return array */ function getSecurityGroups() { $ret = $this->restCall( 'compute', '/os-security-groups', 'GET' ); $groups = array(); $securityGroups = self::_get_property( $ret['body'], 'security_groups' ); if ( !$securityGroups ) { return $groups; } foreach ( $securityGroups as $securityGroup ) { $securityGroupObj = new OpenStackNovaSecurityGroup( $securityGroup ); $groupid = $securityGroupObj->getGroupId(); $groups[$groupid] = $securityGroupObj; } return $groups; } /** * Get the console output of an instance * * @param $instanceid string * @return string */ function getConsoleOutput( $instanceid ) { $instanceid = urlencode( $instanceid ); $data = array( 'os-getConsoleOutput' => array( 'length' => null ) ); $ret = $this->restCall( 'compute', '/servers/' . $instanceid . '/action', 'POST', $data ); if ( $ret['code'] !== 200 ) { return ''; } return self::_get_property( $ret['body'], 'output' ); } /** * @param $volumeId * @return null|OpenStackNovaVolume */ function getVolume( $volumeId ) { # unimplemented return null; } /** * Get all volumes * * @return array */ function getVolumes() { # unimplemented return array(); } /** * @param $instanceName * @param $image * @param $key * @param $instanceType * @param $groups * @return null|OpenStackNovaInstance */ function createInstance( $instanceName, $image, $key, $instanceType, $groups ) { global $wgOpenStackManagerInstanceUserData; $data = array( 'server' => array() ); if ( $key ) { $data['key_name'] = $key; } $data['server']['flavorRef'] = $instanceType; $data['server']['imageRef'] = $image; $data['server']['name'] = $instanceName; if ( $wgOpenStackManagerInstanceUserData ) { $random_hash = md5(date('r', time())); $endl = OpenStackNovaController::getLineEnding(); $boundary = '===============' . $random_hash .'=='; $userdata = 'Content-Type: multipart/mixed; boundary="' . $boundary .'"' . $endl; $userdata .= 'MIME-Version: 1.0' . $endl; $boundary = '--' . $boundary; $userdata .= $endl; $userdata .= $boundary; if ( $wgOpenStackManagerInstanceUserData['cloud-config'] ) { $userdata .= $endl . $this->getAttachmentMime( Spyc::YAMLDump( $wgOpenStackManagerInstanceUserData['cloud-config'] ), 'text/cloud-config', 'cloud-config.txt' ); $userdata .= $endl . $boundary; } if ( $wgOpenStackManagerInstanceUserData['scripts'] ) { foreach ( $wgOpenStackManagerInstanceUserData['scripts'] as $scriptname => $script ) { wfSuppressWarnings(); $stat = stat( $script ); wfRestoreWarnings(); if ( ! $stat ) { continue; } $scripttext = file_get_contents( $script ); $userdata .= $endl . $this->getAttachmentMime( $scripttext, 'text/x-shellscript', $scriptname ); $userdata .= $endl . $boundary; } } if ( $wgOpenStackManagerInstanceUserData['upstarts'] ) { foreach ( $wgOpenStackManagerInstanceUserData['upstarts'] as $upstartname => $upstart ) { wfSuppressWarnings(); $stat = stat( $upstart ); wfRestoreWarnings(); if ( ! $stat ) { continue; } $upstarttext = file_get_contents( $upstart ); $userdata .= $endl . $this->getAttachmentMime( $upstarttext, 'text/upstart-job', $upstartname ); $userdata .= $endl . $boundary; } } $userdata .= '--'; $data['server']['user_data'] = base64_encode( $userdata ); } $data['server']['security_groups'] = array(); foreach ( $groups as $group ) { $data['server']['security_groups'][] = array( 'name' => $group ); } $ret = $this->restCall( 'compute', '/servers', 'POST', $data ); if ( $ret['code'] !== 202 ) { return null; } $instance = new OpenStackNovaInstance( $ret['body']->server, $this->getRegion() ); return $instance; } /** * @param $instanceid * @return bool */ function terminateInstance( $instanceid ) { $addresses = $this->getAddresses(); foreach ( $addresses as $address ) { if ( $address->getInstanceId() === $instanceid ) { $this->disassociateAddress( $instanceid, $address->getPublicIP() ); } } $instanceid = urlencode( $instanceid ); $ret = $this->restCall( 'compute', '/servers/' . $instanceid, 'DELETE' ); return( $ret['code'] === 204 ); } /** * @param $groupname * @param $description * @return null|OpenStackNovaSecurityGroup */ function createSecurityGroup( $groupname, $description ) { $data = array( 'security_group' => array( 'name' => $groupname, 'description' => $description ) ); $ret = $this->restCall( 'compute', '/os-security-groups', 'POST', $data ); if ( $ret['code'] !== 200 ) { return null; } $attr = self::_get_property( $ret['body'], 'security_group' ); if ( !$attr ) { return null; } $securityGroup = new OpenStackNovaSecurityGroup( $attr ); return $securityGroup; } /** * @param $groupid * @return bool */ function deleteSecurityGroup( $groupid ) { $groupid = urlencode( $groupid ); $ret = $this->restCall( 'compute', '/os-security-groups/' . $groupid, 'DELETE' ); return ( $ret['code'] === 202 ); } /** * @param $groupid * @param string $fromport * @param string $toport * @param string $protocol * @param string $range * @param string $group * @return bool */ function addSecurityGroupRule( $groupid, $fromport='', $toport='', $protocol='', $range='', $group='' ) { if ( $group && $range ) { return false; } else if ( $range ) { $data = array( 'security_group_rule' => array ( 'parent_group_id' => (int)$groupid, 'from_port' => $fromport, 'to_port' => $toport, 'ip_protocol' => $protocol, 'cidr' => $range ) ); } else if ( $group ) { $data = array( 'security_group_rule' => array ( 'parent_group_id' => (int)$groupid, 'group_id' => (int)$group ) ); } $ret = $this->restCall( 'compute', '/os-security-group-rules', 'POST', $data ); return ( $ret['code'] === 200 ); } /** * @param $ruleid * @return bool */ function removeSecurityGroupRule( $ruleid ) { $ruleid = urlencode( $ruleid ); $ret = $this->restCall( 'compute', '/os-security-group-rules/' . $ruleid, 'DELETE' ); return ( $ret['code'] === 202 ); } /** * @return null|OpenStackNovaAddress */ function allocateAddress() { $ret = $this->restCall( 'compute', '/os-floating-ips', 'POST', array() ); if ( $ret['code'] !== 200 ) { return null; } $floating_ip = self::_get_property( $ret['body'], 'floating_ip' ); if ( !$floating_ip ) { return null; } $address = new OpenStackNovaAddress( $floating_ip ); return $address; } /** * Release ip address * * @param $id * @return bool */ function releaseAddress( $id ) { $id = urlencode( $id ); $ret = $this->restCall( 'compute', '/os-floating-ips/' . $id, 'DELETE' ); return ( $ret['code'] === 202 ); } /** * Attach new ip address to instance * * @param $instanceid * @param $ip * @return bool */ function associateAddress( $instanceid, $ip ) { $instanceid = urlencode( $instanceid ); $data = array( 'addFloatingIp' => array( 'address' => $ip ) ); $ret = $this->restCall( 'compute', '/servers/' . $instanceid . '/action', 'POST', $data ); return ( $ret['code'] === 202 ); } /** * Disassociate address from an instance * * @param $instanceid * @param $ip * @return bool */ function disassociateAddress( $instanceid, $ip ) { $instanceid = urlencode( $instanceid ); $data = array( 'removeFloatingIp' => array ( 'address' => $ip ) ); $ret = $this->restCall( 'compute', '/servers/' . $instanceid . '/action', 'POST', $data ); return ( $ret['code'] === 202 ); } /** * Create a Nova volume * * @param $zone * @param $size * @param $name * @param $description * @return OpenStackNovaVolume */ function createVolume( $zone, $size, $name, $description ) { # Unimplemented return null; } /** * Delete a Nova volume * * @param $volumeid * @return boolean */ function deleteVolume( $volumeid ) { # unimplemented return false; } /** * Attach a nova volume to the specified device on an instance * * @param volumeid * @param instanceid * @param device * @return boolean */ function attachVolume( $volumeid, $instanceid, $device ) { # unimplemented return false; } /** * Detaches a nova volume from an instance * * @param volumeid * @param force * @return boolean */ function detachVolume( $volumeid, $force ) { # unimplemented return false; } /** * Reboots an instance * * @param type * @param string $type * @return boolean */ function rebootInstance( $instanceid, $type='SOFT' ) { $instanceid = urlencode( $instanceid ); $data = array( 'reboot' => array( 'type' => $type ) ); $ret = $this->restCall( 'compute', '/servers/' . $instanceid . '/action', 'POST', $data ); return ( $ret['code'] === 202 ); } function getLimits() { $ret = $this->restCall( 'compute', '/limits', 'GET', array() ); if ( $ret['code'] !== 200 ) { return null; } $limits = self::_get_property( $ret['body'], 'limits' ); if ( !$limits ) { return null; } $limits = new OpenStackNovaProjectLimits( $limits ); return $limits; } function authenticate( $username, $password ) { - global $wgAuth; global $wgMemc; - $wgAuth->printDebug( "Entering OpenStackNovaController::authenticate", NONSENSITIVE ); + $ldap = LdapAuthenticationPlugin::getInstance(); + $ldap->printDebug( "Entering OpenStackNovaController::authenticate", NONSENSITIVE ); $headers = array( 'Accept: application/json', 'Content-Type: application/json', ); $data = array( 'auth' => array( 'passwordCredentials' => array( 'username' => $username, 'password' => $password ) ) ); $ret = $this->restCall( 'identity', '/tokens', 'POST', $data, $headers ); if ( $ret['code'] !== 200 ) { - $wgAuth->printDebug( "OpenStackNovaController::authenticate return code: " . $ret['code'], NONSENSITIVE ); + $ldap->printDebug( "OpenStackNovaController::authenticate return code: " . $ret['code'], NONSENSITIVE ); return ''; } $user = $ret['body']; $this->token = $this->_get_property( $user->access->token, 'id' ); $key = wfMemcKey( 'openstackmanager', 'fulltoken', $username ); // Expiration time is unneccessary. Token expiration is expected // to be longer than MediaWiki's token, so a re-auth will occur // before the generic token expires. $wgMemc->set( $key, $this->token ); return $this->token; } function getUnscopedToken() { global $wgMemc; $token = ''; $key = wfMemcKey( 'openstackmanager', "fulltoken", $this->username ); $fulltoken = $wgMemc->get( $key ); if ( is_string( $fulltoken ) ) { $token = $fulltoken; } else { if ( !$this->token ) { $wikiuser = User::newFromName( $this->user->getUsername() ); $token = OpenStackNovaUser::loadToken( $wikiuser ); if ( !$token ) { // Log this user out! $wikiuser->doLogout(); return ''; } $wgMemc->set( $key, $token ); } else { $token = $this->token; } } return $token; } function getProjectToken( $project ) { global $wgMemc; // Try to fetch the project token $projectkey = wfMemcKey( 'openstackmanager', "fulltoken-$project", $this->username ); $projecttoken = $wgMemc->get( $projectkey ); if ( is_string( $projecttoken ) ) { return $projecttoken; } $token = $this->getUnscopedToken(); if ( !$token ) { // If there's no non-project token, there's nothing to do, the // user will need to re-authenticate. return ''; } $headers = array( 'Accept: application/json', 'Content-Type: application/json', ); $data = array( 'auth' => array( 'token' => array( 'id' => $token ), 'tenantName' => $project ) ); $path = '/tokens'; $ret = $this->restCall( 'identity', $path, 'POST', $data, $headers ); if ( $ret['code'] !== 200 ) { return ''; } $user = $ret['body']; $token = $this->_get_property( $user->access->token, 'id' ); $expires = strtotime( $this->_get_property( $user->access->token, 'expires' ) ); $wgMemc->set( $projectkey, $token, $expires ); $key = wfMemcKey( 'openstackmanager', 'serviceCatalog-' . $project, $this->username ); $wgMemc->set( $key, json_encode( $user->access->serviceCatalog ), $expires ); return $token; } function getEndpoints( $service ) { global $wgMemc; $key = wfMemcKey( 'openstackmanager', 'serviceCatalog-' . $this->project, $this->username ); $serviceCatalog = json_decode( $wgMemc->get( $key ) ); $endpoints = array(); if ( $serviceCatalog ) { foreach ( $serviceCatalog as $entry ) { if ( $entry->type === $service ) { foreach ( $entry->endpoints as $endpoint ) { $endpoints[] = $endpoint; } } } } return $endpoints; } function getTokenHeaders( $token, $project ) { // Project names can only contain a-z0-9-, strip everything else. $headers = array( 'Accept: application/json', 'Content-Type: application/json', 'X-Auth-Project-Id: ' . preg_replace("/[^a-z0-9-]/", "", $project ), 'X-Auth-Token: ' . $token, ); return $headers; } function restCall( $service, $path, $method, $data = array(), $authHeaders='', $retrying=false ) { - global $wgAuth; global $wgOpenStackManagerNovaIdentityURI; global $wgOpenStackManagerNovaIdentityV3URI; global $wgMemc; + $ldap = LdapAuthenticationPlugin::getInstance(); if ( $authHeaders ) { $headers = $authHeaders; } else { // This isn't an authentication call, we need to get the // tokens and the headers. $token = $this->getProjectToken( $this->getProject() ); $headers = $this->getTokenHeaders( $token, $this->getProject() ); } if ( $service === 'identity' ) { $endpointURL = $wgOpenStackManagerNovaIdentityURI; } elseif ( $service === 'identityv3' ) { $endpointURL = $wgOpenStackManagerNovaIdentityV3URI; } else { $endpoints = $this->getEndpoints( $service ); foreach ( $endpoints as $endpoint ) { if ( $endpoint->region === $this->getRegion() ) { $endpointURL = $endpoint->publicURL; } } } $fullurl = $endpointURL . $path; - $wgAuth->printDebug( "OpenStackNovaController::restCall fullurl: " . $fullurl, NONSENSITIVE ); + $ldap->printDebug( "OpenStackNovaController::restCall fullurl: " . $fullurl, NONSENSITIVE ); $handle = curl_init(); switch( $method ) { case 'GET': if ( $data ) { $fullurl .= '?' . wfArrayToCgi( $data ); } break; case 'POST': curl_setopt( $handle, CURLOPT_POST, true ); curl_setopt( $handle, CURLOPT_POSTFIELDS, json_encode( $data ) ); break; case 'PUT': curl_setopt( $handle, CURLOPT_CUSTOMREQUEST, 'PUT' ); curl_setopt( $handle, CURLOPT_POSTFIELDS, json_encode( $data ) ); break; case 'DELETE': curl_setopt( $handle, CURLOPT_CUSTOMREQUEST, 'DELETE' ); break; } curl_setopt( $handle, CURLOPT_URL, $fullurl ); curl_setopt( $handle, CURLOPT_HTTPHEADER, $headers ); curl_setopt( $handle, CURLOPT_RETURNTRANSFER, true ); curl_setopt( $handle, CURLOPT_HEADER, 1 ); $response = curl_exec( $handle ); $code = curl_getinfo( $handle, CURLINFO_HTTP_CODE ); if ( $code === 401 && !$retrying ) { $wgMemc->delete( wfMemcKey( 'openstackmanager', "fulltoken-" . $this->getProject(), $this->username ) ); return $this->restCall( $service, $path, $method, $data, $authHeaders, true ); } $header_size = curl_getinfo( $handle, CURLINFO_HEADER_SIZE ); $response_headers = substr( $response, 0, $header_size ); $body = substr( $response, $header_size ); $body = json_decode( $body ); return array( 'code' => $code, 'body' => $body, 'response_headers' => $response_headers ); } static function _get_property( $object, $id ) { if ( isset( $object ) && is_object( $object ) ) { if ( property_exists( $object, $id ) ) { return $object->$id; } } return null; } } diff --git a/nova/OpenStackNovaDomain.php b/nova/OpenStackNovaDomain.php index 681abbe..37a0849 100644 --- a/nova/OpenStackNovaDomain.php +++ b/nova/OpenStackNovaDomain.php @@ -1,310 +1,309 @@ domainname = $domainname; OpenStackNovaLdapConnection::connect(); $this->fetchDomainInfo(); } /** * Fetch the domain from LDAP and initialize the object * * @return void */ function fetchDomainInfo() { - global $wgAuth, $wgMemc; + global $wgMemc; global $wgOpenStackManagerLDAPInstanceBaseDN; $key = wfMemcKey( 'openstackmanager', 'domaininfo', $this->domainname ); $domainInfo = $wgMemc->get( $key ); if ( is_array( $domainInfo ) ) { $this->domainInfo = $domainInfo; } else { - $result = LdapAuthenticationPlugin::ldap_search( $wgAuth->ldapconn, $wgOpenStackManagerLDAPInstanceBaseDN, + $ldap = LdapAuthenticationPlugin::getInstance(); + $result = LdapAuthenticationPlugin::ldap_search( $ldap->ldapconn, $wgOpenStackManagerLDAPInstanceBaseDN, '(dc=' . $this->domainname . ')' ); - $this->domainInfo = LdapAuthenticationPlugin::ldap_get_entries( $wgAuth->ldapconn, $result ); + $this->domainInfo = LdapAuthenticationPlugin::ldap_get_entries( $ldap->ldapconn, $result ); $wgMemc->set( $key, $this->domainInfo, 3600 * 24 ); } if ( $this->domainInfo ) { $this->fqdn = $this->domainInfo[0]['associateddomain'][0]; $this->domainDN = $this->domainInfo[0]['dn']; } } /** * Return the short domainname * * @return string */ function getDomainName() { return $this->domainname; } /** * Return the fully qualified domain name * * @return string */ function getFullyQualifiedDomainName() { return $this->fqdn; } /** * Return the location associated with this domain; if this domain * is a public domain, return an empty string * * @return string */ function getLocation() { if ( isset( $this->domainInfo[0]['l'] ) ) { return $this->domainInfo[0]['l'][0]; } else { return ''; } } /** * Update the Start of Authority record. This should be called on * the change of any object in the domain * * @return bool */ function updateSOA() { - global $wgAuth; - + $ldap = LdapAuthenticationPlugin::getInstance(); $domain = array(); $domain['soarecord'] = OpenStackNovaDomain::generateSOA(); - $success = LdapAuthenticationPlugin::ldap_modify( $wgAuth->ldapconn, $this->domainDN, $domain ); + $success = LdapAuthenticationPlugin::ldap_modify( $ldap->ldapconn, $this->domainDN, $domain ); if ( $success ) { - $wgAuth->printDebug( "Successfully modified soarecord for " . $this->domainDN, NONSENSITIVE ); + $ldap->printDebug( "Successfully modified soarecord for " . $this->domainDN, NONSENSITIVE ); $this->fetchDomainInfo(); return true; } else { - $wgAuth->printDebug( "Failed to modify soarecord for " . $this->domainDN, NONSENSITIVE ); + $ldap->printDebug( "Failed to modify soarecord for " . $this->domainDN, NONSENSITIVE ); return false; } } /** * Get all domains of a specific type. Valid types are local, public, and all. * * @static * @param string $type * @return array of OpenNovaDomain */ static function getAllDomains( $type='all' ) { - global $wgAuth; global $wgOpenStackManagerLDAPInstanceBaseDN; + $ldap = LdapAuthenticationPlugin::getInstance(); OpenStackNovaLdapConnection::connect(); $domains = array(); if ( $type === 'local' ) { $query = '(&(soarecord=*)(l=*))'; } elseif ( $type === 'public' ) { $query = '(&(soarecord=*)(!(l=*)))'; } else { $query = '(soarecord=*)'; } - $result = LdapAuthenticationPlugin::ldap_search( $wgAuth->ldapconn, $wgOpenStackManagerLDAPInstanceBaseDN, $query ); + $result = LdapAuthenticationPlugin::ldap_search( $ldap->ldapconn, $wgOpenStackManagerLDAPInstanceBaseDN, $query ); if ( $result ) { - $entries = LdapAuthenticationPlugin::ldap_get_entries( $wgAuth->ldapconn, $result ); + $entries = LdapAuthenticationPlugin::ldap_get_entries( $ldap->ldapconn, $result ); if ( $entries ) { # First entry is always a count array_shift( $entries ); foreach ( $entries as $entry ) { $domain = new OpenStackNovaDomain( $entry['dc'][0] ); $domains[] = $domain; } } } return $domains; } /** * Get a domain object by short name. If the domain is not found * return null. * * @static * @param $domainname * @return null|OpenStackNovaDomain */ static function getDomainByName( $domainname ) { $domain = new OpenStackNovaDomain( $domainname ); if ( $domain->domainInfo ) { return $domain; } else { return null; } } /** * Find a domain by a host entry's IP address. If the host entry doesn't * exist, return null. * * @static * @param $ip * @return null|OpenStackNovaDomain */ static function getDomainByHostIP( $ip ) { - global $wgAuth; global $wgOpenStackManagerLDAPInstanceBaseDN; + $ldap = LdapAuthenticationPlugin::getInstance(); OpenStackNovaLdapConnection::connect(); - $result = LdapAuthenticationPlugin::ldap_search( $wgAuth->ldapconn, $wgOpenStackManagerLDAPInstanceBaseDN, + $result = LdapAuthenticationPlugin::ldap_search( $ldap->ldapconn, $wgOpenStackManagerLDAPInstanceBaseDN, '(arecord=' . $ip . ')' ); - $hostInfo = LdapAuthenticationPlugin::ldap_get_entries( $wgAuth->ldapconn, $result ); + $hostInfo = LdapAuthenticationPlugin::ldap_get_entries( $ldap->ldapconn, $result ); if ( $hostInfo['count'] == "0" ) { return null; } $fqdn = $hostInfo[0]['associateddomain'][0]; $domainname = explode( '.', $fqdn ); $domainname = $domainname[1]; $domain = new OpenStackNovaDomain( $domainname ); if ( $domain->domainInfo ) { return $domain; } else { return null; } } /** * Get a domain by a region. Return null if the region * does not exist. * * @static * @param $instanceid * @return null|OpenStackNovaDomain */ static function getDomainByRegion( $region ) { $domain = OpenStackNovaDomain::getDomainByName( $region ); if ( $domain ) { if ( $domain->getLocation() ) { return $domain; } } return null; } # TODO: Allow generic domains; get rid of config set base name /** * Create a new domain based on shortname, fully qualified domain name * and location. If location is an empty string, the domain created will * be a public domain, otherwise it will be a private domain for instance * creation. Returns null on domain creation failure. * * @static * @param $domainname * @param $fqdn * @param $location * @return null|OpenStackNovaDomain */ static function createDomain( $domainname, $fqdn, $location ) { - global $wgAuth; global $wgOpenStackManagerLDAPInstanceBaseDN; + $ldap = LdapAuthenticationPlugin::getInstance(); OpenStackNovaLdapConnection::connect(); $soa = OpenStackNovaDomain::generateSOA(); $domain = array(); $domain['objectclass'][] = 'dcobject'; $domain['objectclass'][] = 'dnsdomain'; $domain['objectclass'][] = 'domainrelatedobject'; $domain['dc'] = $domainname; $domain['soarecord'] = $soa; $domain['associateddomain'] = $fqdn; if ( $location ) { $domain['l'] = $location; } $dn = 'dc=' . $domainname . ',' . $wgOpenStackManagerLDAPInstanceBaseDN; - $success = LdapAuthenticationPlugin::ldap_add( $wgAuth->ldapconn, $dn, $domain ); + $success = LdapAuthenticationPlugin::ldap_add( $ldap->ldapconn, $dn, $domain ); if ( $success ) { - $wgAuth->printDebug( "Successfully added domain $domainname", NONSENSITIVE ); + $ldap->printDebug( "Successfully added domain $domainname", NONSENSITIVE ); return new OpenStackNovaDomain( $domainname ); } else { - $wgAuth->printDebug( "Failed to add domain $domainname", NONSENSITIVE ); + $ldap->printDebug( "Failed to add domain $domainname", NONSENSITIVE ); return null; } } /** * Deletes a domain based on the domain's short name. Will fail to * delete the domain if any host entries still exist in the domain. * * @static * @param $domainname * @return bool */ static function deleteDomain( $domainname ) { - global $wgAuth; - + $ldap = LdapAuthenticationPlugin::getInstance(); OpenStackNovaLdapConnection::connect(); $domain = new OpenStackNovaDomain( $domainname ); if ( ! $domain ) { - $wgAuth->printDebug( "Domain $domainname does not exist", NONSENSITIVE ); + $ldap->printDebug( "Domain $domainname does not exist", NONSENSITIVE ); return array( false, 'openstackmanager-failedeletedomainnotfound' ); } $dn = $domain->domainDN; # Domains can have records as sub entries. If sub-entries exist, fail. - $result = LdapAuthenticationPlugin::ldap_list( $wgAuth->ldapconn, $dn, 'objectclass=*' ); - $hosts = LdapAuthenticationPlugin::ldap_get_entries( $wgAuth->ldapconn, $result ); + $result = LdapAuthenticationPlugin::ldap_list( $ldap->ldapconn, $dn, 'objectclass=*' ); + $hosts = LdapAuthenticationPlugin::ldap_get_entries( $ldap->ldapconn, $result ); if ( $hosts['count'] != "0" ) { - $wgAuth->printDebug( "Failed to delete domain $domainname, since it had sub entries", NONSENSITIVE ); + $ldap->printDebug( "Failed to delete domain $domainname, since it had sub entries", NONSENSITIVE ); return array( false, 'openstackmanager-failedeletedomainduplicates' ); } - $success = LdapAuthenticationPlugin::ldap_delete( $wgAuth->ldapconn, $dn ); + $success = LdapAuthenticationPlugin::ldap_delete( $ldap->ldapconn, $dn ); if ( $success ) { - $wgAuth->printDebug( "Successfully deleted domain $domainname", NONSENSITIVE ); + $ldap->printDebug( "Successfully deleted domain $domainname", NONSENSITIVE ); return array( true, '' ); } else { - $wgAuth->printDebug( "Failed to delete domain $domainname, since it had sub entries", NONSENSITIVE ); + $ldap->printDebug( "Failed to delete domain $domainname, since it had sub entries", NONSENSITIVE ); return array( false, 'openstackmanager-failedeletedomain' ); } } /** * Generates a valid SOA string based on configuration and current time. * * @static * @return string */ static function generateSOA() { global $wgOpenStackManagerDNSOptions; $serial = date( 'U' ); $soa = $wgOpenStackManagerDNSOptions['servers']['primary'] . '. ' . $wgOpenStackManagerDNSOptions['soa']['hostmaster'] . '. ' . $serial . ' ' . $wgOpenStackManagerDNSOptions['soa']['refresh'] . ' ' . $wgOpenStackManagerDNSOptions['soa']['retry'] . ' ' . $wgOpenStackManagerDNSOptions['soa']['expiry'] . ' ' . $wgOpenStackManagerDNSOptions['soa']['minimum']; return $soa; } } diff --git a/nova/OpenStackNovaHost.php b/nova/OpenStackNovaHost.php index 535f7d2..438e561 100644 --- a/nova/OpenStackNovaHost.php +++ b/nova/OpenStackNovaHost.php @@ -1,431 +1,424 @@ hostInfo[0]['arecord'] ) ) { $arecords = $this->hostInfo[0]['arecord']; array_shift( $arecords ); } return $arecords; } /** * Return all associateddomain records associated with this host. * Return an empty array if the arecord attribute is not set. * * @return array */ function getAssociatedDomains() { $associateddomain = array(); if ( isset( $this->hostInfo[0]['associateddomain'] ) ) { $associateddomain = $this->hostInfo[0]['associateddomain']; array_shift( $associateddomain ); } return $associateddomain; } /** * Return all cname records associated with this host. * Return an empty array if the arecord attribute is not set. * * @return array */ function getCNAMERecords() { $cnamerecords = array(); if ( isset( $this->hostInfo[0]['cnamerecord'] ) ) { $cnamerecords = $this->hostInfo[0]['cnamearecord']; array_shift( $cnamerecords ); } return $cnamerecords; } /** * Remove an associated domain record from this entry. * * @param $fqdn * @return bool */ function deleteAssociatedDomain( $fqdn ) { - global $wgAuth; - if ( isset( $this->hostInfo[0]['associateddomain'] ) ) { + $ldap = LdapAuthenticationPlugin::getInstance(); $associateddomains = $this->hostInfo[0]['associateddomain']; array_shift( $associateddomains ); $index = array_search( $fqdn, $associateddomains ); if ( $index === false ) { - $wgAuth->printDebug( "Failed to find $fqdn in associateddomain list", NONSENSITIVE ); + $ldap->printDebug( "Failed to find $fqdn in associateddomain list", NONSENSITIVE ); return false; } unset( $associateddomains[$index] ); $values = array(); $values['associateddomain'] = array(); foreach ( $associateddomains as $associateddomain ) { $values['associateddomain'][] = $associateddomain; } - $success = LdapAuthenticationPlugin::ldap_modify( $wgAuth->ldapconn, $this->hostDN, $values ); + $success = LdapAuthenticationPlugin::ldap_modify( $ldap->ldapconn, $this->hostDN, $values ); if ( $success ) { - $wgAuth->printDebug( "Successfully removed $fqdn from $this->hostDN", NONSENSITIVE ); + $ldap->printDebug( "Successfully removed $fqdn from $this->hostDN", NONSENSITIVE ); $this->getDomain()->updateSOA(); $this->fetchHostInfo(); return true; } else { - $wgAuth->printDebug( "Failed to remove $fqdn from $this->hostDN", NONSENSITIVE ); + $ldap->printDebug( "Failed to remove $fqdn from $this->hostDN", NONSENSITIVE ); return false; } } else { return false; } } /** * Remove an arecord from the host. * * @param $ip * @return bool */ function deleteARecord( $ip ) { - global $wgAuth; - if ( isset( $this->hostInfo[0]['arecord'] ) ) { + $ldap = LdapAuthenticationPlugin::getInstance(); $arecords = $this->hostInfo[0]['arecord']; array_shift( $arecords ); $index = array_search( $ip, $arecords ); if ( $index === false ) { - $wgAuth->printDebug( "Failed to find ip address in arecords list", NONSENSITIVE ); + $ldap->printDebug( "Failed to find ip address in arecords list", NONSENSITIVE ); return false; } unset( $arecords[$index] ); $values = array(); $values['arecord'] = array(); foreach ( $arecords as $arecord ) { $values['arecord'][] = $arecord; } - $success = LdapAuthenticationPlugin::ldap_modify( $wgAuth->ldapconn, $this->hostDN, $values ); + $success = LdapAuthenticationPlugin::ldap_modify( $ldap->ldapconn, $this->hostDN, $values ); if ( $success ) { - $wgAuth->printDebug( "Successfully removed $ip from $this->hostDN", NONSENSITIVE ); + $ldap->printDebug( "Successfully removed $ip from $this->hostDN", NONSENSITIVE ); $this->getDomain()->updateSOA(); $this->fetchHostInfo(); return true; } else { - $wgAuth->printDebug( "Failed to remove $ip from $this->hostDN", NONSENSITIVE ); + $ldap->printDebug( "Failed to remove $ip from $this->hostDN", NONSENSITIVE ); return false; } } else { return false; } } /** * Add an associated domain record to this host. * * @param $fqdn * @return bool */ function addAssociatedDomain( $fqdn ) { - global $wgAuth; - + $ldap = LdapAuthenticationPlugin::getInstance(); $associatedomains = array(); if ( isset( $this->hostInfo[0]['associateddomain'] ) ) { $associatedomains = $this->hostInfo[0]['associateddomain']; array_shift( $associatedomains ); } $associatedomains[] = $fqdn; $values = array(); $values['associateddomain'] = $associatedomains; - $success = LdapAuthenticationPlugin::ldap_modify( $wgAuth->ldapconn, $this->hostDN, $values ); + $success = LdapAuthenticationPlugin::ldap_modify( $ldap->ldapconn, $this->hostDN, $values ); if ( $success ) { - $wgAuth->printDebug( "Successfully added $fqdn to $this->hostDN", NONSENSITIVE ); + $ldap->printDebug( "Successfully added $fqdn to $this->hostDN", NONSENSITIVE ); $this->getDomain()->updateSOA(); $this->fetchHostInfo(); return true; } else { - $wgAuth->printDebug( "Failed to add $fqdn to $this->hostDN", NONSENSITIVE ); + $ldap->printDebug( "Failed to add $fqdn to $this->hostDN", NONSENSITIVE ); return false; } } /** * Add an arecord entry to this host. * * @param $ip * @return bool */ function addARecord( $ip ) { - global $wgAuth; - + $ldap = LdapAuthenticationPlugin::getInstance(); $arecords = array(); if ( isset( $this->hostInfo[0]['arecord'] ) ) { $arecords = $this->hostInfo[0]['arecord']; array_shift( $arecords ); } $arecords[] = $ip; $values = array(); $values['arecord'] = $arecords; - $success = LdapAuthenticationPlugin::ldap_modify( $wgAuth->ldapconn, $this->hostDN, $values ); + $success = LdapAuthenticationPlugin::ldap_modify( $ldap->ldapconn, $this->hostDN, $values ); if ( $success ) { - $wgAuth->printDebug( "Successfully added $ip to $this->hostDN", NONSENSITIVE ); + $ldap->printDebug( "Successfully added $ip to $this->hostDN", NONSENSITIVE ); $this->getDomain()->updateSOA(); $this->fetchHostInfo(); return true; } else { - $wgAuth->printDebug( "Failed to add $ip to $this->hostDN", NONSENSITIVE ); + $ldap->printDebug( "Failed to add $ip to $this->hostDN", NONSENSITIVE ); return false; } } /** * Replace all arecords on this host with $ip. * * @param $ip * @return bool */ function setARecord( $ip ) { - global $wgAuth; - + $ldap = LdapAuthenticationPlugin::getInstance(); $values = array( 'arecord' => array( $ip ) ); - $success = LdapAuthenticationPlugin::ldap_modify( $wgAuth->ldapconn, $this->hostDN, $values ); + $success = LdapAuthenticationPlugin::ldap_modify( $ldap->ldapconn, $this->hostDN, $values ); if ( $success ) { - $wgAuth->printDebug( "Successfully set $ip on $this->hostDN", NONSENSITIVE ); + $ldap->printDebug( "Successfully set $ip on $this->hostDN", NONSENSITIVE ); $this->getDomain()->updateSOA(); $this->fetchHostInfo(); return true; } else { - $wgAuth->printDebug( "Failed to set $ip on $this->hostDN", NONSENSITIVE ); + $ldap->printDebug( "Failed to set $ip on $this->hostDN", NONSENSITIVE ); return false; } } /** * Get a public host by the host's ip. Returns * null if the entry does not exist. * * @static * @param $ip * @return OpenStackNovaHost */ static function getHostByPublicIP( $ip ) { - global $wgAuth; - $host = new OpenStackNovaPublicHost( $ip ); if ( $host->hostInfo ) { return $host; } else { return null; } } /** * Get a host by an instance ID. Returns null if the entry does not exist. * * @static * @param $instancename * @param $instanceproject * @param $region * @return OpenStackNovaHost */ static function getHostByNameAndProject( $instancename, $instanceproject, $region ) { $host = new OpenStackNovaPrivateHost( $instancename, $instanceproject, $region ); if ( $host->hostInfo ) { return $host; } else { return null; } } /** * Delete this host * * @return bool */ function deleteHost() { - global $wgAuth; + $ldap = LdapAuthenticationPlugin::getInstance(); # Grab the domain now, before we delete the entry and it's no longer there to grab. $domain = $this->getDomain(); - $success = LdapAuthenticationPlugin::ldap_delete( $wgAuth->ldapconn, $this->hostDN ); + $success = LdapAuthenticationPlugin::ldap_delete( $ldap->ldapconn, $this->hostDN ); if ( $success ) { $domain->updateSOA(); - $wgAuth->printDebug( "Successfully deleted host $this->hostDN", NONSENSITIVE ); + $ldap->printDebug( "Successfully deleted host $this->hostDN", NONSENSITIVE ); return true; } else { - $wgAuth->printDebug( "Failed to delete host $this->hostDN", NONSENSITIVE ); + $ldap->printDebug( "Failed to delete host $this->hostDN", NONSENSITIVE ); return false; } } /** * Add a new host entry from an OpenStackNovaInstance object, an OpenStackNovaDomain object, * and optional puppet information. Returns null if a host already exists, or if * if the host additional fails. This function should be used for adding host entries * for instances (private DNS). * * @static * @param $instance OpenStackNovaInstance * @param $domain OpenStackNovaDomain * @param $puppetinfo * @return OpenStackNovaHost */ static function addHostFromInstance( $instance, $domain, $puppetinfo = array() ) { - global $wgAuth; global $wgOpenStackManagerLDAPInstanceBaseDN, $wgOpenStackManagerPuppetOptions; + $ldap = LdapAuthenticationPlugin::getInstance(); OpenStackNovaLdapConnection::connect(); $hostname = $instance->getInstanceName(); $instanceid = $instance->getInstanceId(); $instancename = $instance->getInstanceName(); $instanceproject = $instance->getProject(); $project = $instance->getProject(); $tmpip = $instance->getInstancePrivateIPs(); if ( $tmpip && isset( $tmpip[0] ) ) { $ip = $tmpip[0]; } else { $ip = null; } $domainname = $domain->getFullyQualifiedDomainName(); $region = $domain->getLocation(); $fqdn = $instancename . '.' . $instanceproject . '.' . $domainname; $host = OpenStackNovaHost::getHostByNameAndProject( $instancename, $instanceproject, $region ); if ( $host ) { - $wgAuth->printDebug( "Failed to add host $hostname as the DNS entry already exists", NONSENSITIVE ); + $ldap->printDebug( "Failed to add host $hostname as the DNS entry already exists", NONSENSITIVE ); return null; } $hostEntry = array(); $hostEntry['objectclass'][] = 'dcobject'; $hostEntry['objectclass'][] = 'dnsdomain'; $hostEntry['objectclass'][] = 'domainrelatedobject'; $hostEntry['dc'] = $fqdn; # $hostEntry['l'] = $instance->getInstanceAvailabilityZone(); if ( $ip ) { $hostEntry['arecord'] = $ip; } $hostEntry['associateddomain'][] = $instanceid . '.' . $domainname; $hostEntry['associateddomain'][] = $hostname . '.' . $domainname; $hostEntry['associateddomain'][] = $instanceid . '.' . $project . '.' . $domainname; $hostEntry['associateddomain'][] = $hostname . '.' . $project . '.' . $domainname; $hostEntry['l'] = $domain->getLocation(); if ( $wgOpenStackManagerPuppetOptions['enabled'] ) { $hostEntry['objectclass'][] = 'puppetclient'; foreach ( $wgOpenStackManagerPuppetOptions['defaultclasses'] as $class ) { $hostEntry['puppetclass'][] = $class; } foreach ( $wgOpenStackManagerPuppetOptions['defaultvariables'] as $variable => $value ) { $hostEntry['puppetvar'][] = $variable . '=' . $value; } if ( $puppetinfo ) { if ( isset( $puppetinfo['classes'] ) ) { foreach ( $puppetinfo['classes'] as $class ) { $hostEntry['puppetclass'][] = $class; } } if ( isset( $puppetinfo['variables'] ) ) { foreach ( $puppetinfo['variables'] as $variable => $value ) { if ( $value ) { $hostEntry['puppetvar'][] = $variable . '=' . $value; } } } } $hostEntry['puppetvar'][] = 'instanceproject=' . $project; $hostEntry['puppetvar'][] = 'instancename=' . $hostname; } $dn = 'dc=' . $fqdn . ',' . $wgOpenStackManagerLDAPInstanceBaseDN; - $success = LdapAuthenticationPlugin::ldap_add( $wgAuth->ldapconn, $dn, $hostEntry ); + $success = LdapAuthenticationPlugin::ldap_add( $ldap->ldapconn, $dn, $hostEntry ); if ( $success ) { $domain->updateSOA(); - $wgAuth->printDebug( "Successfully added host $fqdn", NONSENSITIVE ); + $ldap->printDebug( "Successfully added host $fqdn", NONSENSITIVE ); return OpenStackNovaHost::getHostByInstanceNameAndProject( $instancename, $instanceproject, $region ); } else { - $wgAuth->printDebug( "Failed to add host $fqdn with dn of $dn", NONSENSITIVE ); + $ldap->printDebug( "Failed to add host $fqdn with dn of $dn", NONSENSITIVE ); return null; } } /** * Adds a host entry based on the hostname, IP addrss, and a domain. Returns null * if the entry already exists, or if the additional fails. This function should be used * for adding public DNS entries. * * @static * @param $hostname * @param $ip * @param $domain OpenStackNovaDomain * @return bool|null|OpenStackNovaHost */ static function addPublicHost( $hostname, $ip, $domain ) { - global $wgAuth; global $wgOpenStackManagerLDAPInstanceBaseDN; + $ldap = LdapAuthenticationPlugin::getInstance(); OpenStackNovaLdapConnection::connect(); $domainname = $domain->getFullyQualifiedDomainName(); $host = OpenStackNovaHost::getHostByPublicIP( $ip ); if ( $host ) { - $wgAuth->printDebug( "Failed to add public host $hostname as the DNS entry already exists", NONSENSITIVE ); + $ldap->printDebug( "Failed to add public host $hostname as the DNS entry already exists", NONSENSITIVE ); return null; } $hostEntry = array(); $hostEntry['objectclass'][] = 'dcobject'; $hostEntry['objectclass'][] = 'dnsdomain'; $hostEntry['objectclass'][] = 'domainrelatedobject'; $hostEntry['dc'] = $ip; $hostEntry['arecord'] = $ip; $hostEntry['associateddomain'][] = $hostname . '.' . $domainname; $dn = 'dc=' . $ip . ',' . $wgOpenStackManagerLDAPInstanceBaseDN; - $success = LdapAuthenticationPlugin::ldap_add( $wgAuth->ldapconn, $dn, $hostEntry ); + $success = LdapAuthenticationPlugin::ldap_add( $ldap->ldapconn, $dn, $hostEntry ); if ( $success ) { $domain->updateSOA(); - $wgAuth->printDebug( "Successfully added public host $hostname", NONSENSITIVE ); + $ldap->printDebug( "Successfully added public host $hostname", NONSENSITIVE ); return new OpenStackNovaHost( false, null, $ip ); } else { - $wgAuth->printDebug( "Failed to add public host $hostname with dn = $dn", NONSENSITIVE ); + $ldap->printDebug( "Failed to add public host $hostname with dn = $dn", NONSENSITIVE ); return null; } } /** * @param $hostname * @return bool */ static function validateHostname( $hostname ) { # Does not handle trailing dots, purposely return (bool)preg_match( "/^(?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|\b-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|\b-){0,61}[0-9A-Za-z])?)*$/", $hostname ); } } diff --git a/nova/OpenStackNovaLdapConnection.php b/nova/OpenStackNovaLdapConnection.php index d744ac6..b2009fa 100644 --- a/nova/OpenStackNovaLdapConnection.php +++ b/nova/OpenStackNovaLdapConnection.php @@ -1,25 +1,25 @@ boundAs !== $wgOpenStackManagerLDAPUser ) { - $wgAuth->connect( $wgOpenStackManagerLDAPDomain ); - $wgAuth->bindAs( $wgOpenStackManagerLDAPUser, $wgOpenStackManagerLDAPUserPassword ); + $ldap = LdapAuthenticationPlugin::getInstance(); + if ( $ldap->boundAs !== $wgOpenStackManagerLDAPUser ) { + $ldap->connect( $wgOpenStackManagerLDAPDomain ); + $ldap->bindAs( $wgOpenStackManagerLDAPUser, $wgOpenStackManagerLDAPUserPassword ); } } } diff --git a/nova/OpenStackNovaPrivateHost.php b/nova/OpenStackNovaPrivateHost.php index 31e2d09..718deae 100644 --- a/nova/OpenStackNovaPrivateHost.php +++ b/nova/OpenStackNovaPrivateHost.php @@ -1,195 +1,192 @@ instancename = $wgAuth->getLdapEscapedString( $instancename ); - $this->instanceproject = $wgAuth->getLdapEscapedString( $instanceproject ); + $ldap = LdapAuthenticationPlugin::getInstance(); + $this->instancename = $ldap->getLdapEscapedString( $instancename ); + $this->instanceproject = $ldap->getLdapEscapedString( $instanceproject ); $this->region = $region; $this->domainCache = null; OpenStackNovaLdapConnection::connect(); $this->fetchHostInfo(); } /** * Fetch the host from LDAP and initialize the object * * @return void */ function fetchHostInfo() { - global $wgAuth; global $wgOpenStackManagerLDAPInstanceBaseDN; + $ldap = LdapAuthenticationPlugin::getInstance(); if ($this->getDomain()) { $fqdn = $this->instancename . '.' . $this->instanceproject . '.' . $this->getDomain()->getFullyQualifiedDomainName(); } else { # No domain means no instance! $this->hostInfo = null; return; } - $result = LdapAuthenticationPlugin::ldap_search( $wgAuth->ldapconn, $wgOpenStackManagerLDAPInstanceBaseDN, '(dc=' . $fqdn . ')' ); - $this->hostInfo = LdapAuthenticationPlugin::ldap_get_entries( $wgAuth->ldapconn, $result ); + $result = LdapAuthenticationPlugin::ldap_search( $ldap->ldapconn, $wgOpenStackManagerLDAPInstanceBaseDN, '(dc=' . $fqdn . ')' ); + $this->hostInfo = LdapAuthenticationPlugin::ldap_get_entries( $ldap->ldapconn, $result ); if ( $this->hostInfo["count"] == "0" ) { $this->hostInfo = null; } else { $this->hostDN = $this->hostInfo[0]['dn']; } } /** * Return a private host's host's fully qualified display name * * (Note that calling this for a public host doesn't make sense since public * host entries have multiple FQDNs.) * * @return string */ function getFullyQualifiedDisplayName() { - global $wgAuth; - if ($this->getDomain()) { $fqdn = $this->instancename . '.' . $this->instanceproject . '.' . $this->getDomain()->getFullyQualifiedDomainName(); return $fqdn; } else { - $wgAuth->printDebug( "Error: Unable to determine instancename of " . $this->instancename, NONSENSITIVE ); + $ldap = LdapAuthenticationPlugin::getInstance(); + $ldap->printDebug( "Error: Unable to determine instancename of " . $this->instancename, NONSENSITIVE ); return ""; } } /** * Return the domain associated with this host * * @return OpenStackNovaDomain */ function getDomain() { - global $wgAuth; - if ( ! $this->domainCache ) { $this->domainCache = OpenStackNovaDomain::getDomainByRegion( $this->region ); if (! $this->domainCache ) { - $wgAuth->printDebug( "Looked up domain for region $this->region but domainCache is still empty.", NONSENSITIVE ); + $ldap = LdapAuthenticationPlugin::getInstance(); + $ldap->printDebug( "Looked up domain for region $this->region but domainCache is still empty.", NONSENSITIVE ); } } return $this->domainCache; } /** * Return human-readable hostname * * @return string */ function getDisplayName() { $pieces = explode( '.', $this->getFullyQualifiedDisplayName() ); return $pieces[0]; } /** * * Return .. for a private host * * (Note that calling this for a public host doesn't make sense since public * host entries have multiple FQDNs.) * * @return string */ function getFullyQualifiedHostName() { return $this->getFullyQualifiedDisplayName(); } /** * Return the puppet classes and variables assigned to this host * * @return array */ function getPuppetConfiguration() { $puppetinfo = array( 'puppetclass' => array(), 'puppetvar' => array() ); if ( isset( $this->hostInfo[0]['puppetclass'] ) ) { array_shift( $this->hostInfo[0]['puppetclass'] ); foreach ( $this->hostInfo[0]['puppetclass'] as $class ) { $puppetinfo['puppetclass'][] = $class; } } if ( isset( $this->hostInfo[0]['puppetvar'] ) ) { array_shift( $this->hostInfo[0]['puppetvar'] ); foreach ( $this->hostInfo[0]['puppetvar'] as $variable ) { $vararr = explode( '=', $variable ); $varname = trim( $vararr[0] ); $var = trim( $vararr[1] ); $puppetinfo['puppetvar'][$varname] = $var; } } return $puppetinfo; } /** * Update puppet classes and variables for this host. * * @param $puppetinfo * @return bool */ function modifyPuppetConfiguration( $puppetinfo ) { - global $wgAuth; global $wgOpenStackManagerPuppetOptions; $hostEntry = array( 'puppetclass' => array(), 'puppetvar' => array() ); if ( $wgOpenStackManagerPuppetOptions['enabled'] ) { + $ldap = LdapAuthenticationPlugin::getInstance(); if ( isset( $puppetinfo['classes'] ) ) { foreach ( $puppetinfo['classes'] as $class ) { $hostEntry['puppetclass'][] = $class; } } if ( isset( $puppetinfo['variables'] ) ) { foreach ( $puppetinfo['variables'] as $variable => $value ) { $hostEntry['puppetvar'][] = $variable . '=' . $value; } } $oldpuppetinfo = $this->getPuppetConfiguration(); if ( isset( $oldpuppetinfo['puppetvar'] ) ) { - $wgAuth->printDebug( "Checking for preexisting variables", NONSENSITIVE ); + $ldap->printDebug( "Checking for preexisting variables", NONSENSITIVE ); foreach ( $oldpuppetinfo['puppetvar'] as $variable => $value ) { - $wgAuth->printDebug( "Found $variable", NONSENSITIVE ); + $ldap->printDebug( "Found $variable", NONSENSITIVE ); if ( $variable === "instanceproject" || $variable === "instancename" ) { $hostEntry['puppetvar'][] = $variable . '=' . $value; } } } - $success = LdapAuthenticationPlugin::ldap_modify( $wgAuth->ldapconn, $this->hostDN, $hostEntry ); + $success = LdapAuthenticationPlugin::ldap_modify( $ldap->ldapconn, $this->hostDN, $hostEntry ); if ( $success ) { $this->fetchHostInfo(); - $wgAuth->printDebug( "Successfully modified puppet configuration for host", NONSENSITIVE ); + $ldap->printDebug( "Successfully modified puppet configuration for host", NONSENSITIVE ); return true; } else { - $wgAuth->printDebug( "Failed to modify puppet configuration for host", NONSENSITIVE ); + $ldap->printDebug( "Failed to modify puppet configuration for host", NONSENSITIVE ); return false; } } return false; } } diff --git a/nova/OpenStackNovaProject.php b/nova/OpenStackNovaProject.php index ef10c38..8f938ac 100644 --- a/nova/OpenStackNovaProject.php +++ b/nova/OpenStackNovaProject.php @@ -1,939 +1,938 @@ projectid = $projectid; $this->projectname = ""; if ( $load ) { $this->fetchProjectInfo(); } else { $this->loaded = false; } } public function setName( $projectname ) { $this->projectname = $projectname; } public function getName() { if ( !$this->projectname ) { $this->loadProjectName(); } return $this->projectname; } public function getId() { return $this->projectid; } function loadProjectName() { global $wgOpenStackManagerLDAPProjectBaseDN; global $wgMemc; $key = wfMemcKey( 'openstackmanager', 'projectname', $this->projectid ); $this->projectname = $wgMemc->get( $key ); if ( ! $this->projectname ) { $controller = OpenstackNovaProject::getController(); $this->projectname = $controller->getProjectName( $this->projectid ); # Projectname doesn't ever change once a project is created, so # we can cache this a good long time. $wgMemc->set( $key, $this->projectname ); } # We still keep things like sudoers in ldap, so we need a unique dn for this # project to keep things under. $this->projectDN = 'cn=' . $this->projectname . ',' . $wgOpenStackManagerLDAPProjectBaseDN; } /** * Fetch the project from keystone initialize the object * @return void */ function fetchProjectInfo( $refresh=true ) { - global $wgAuth; global $wgOpenStackManagerLDAPProjectBaseDN; if ( $this->loaded and !$refresh ) { return; } if ( !$this->projectname || $refresh ) { $this->loadProjectName(); } $this->roles = array(); foreach ( self::$visiblerolenames as $rolename ) { $this->roles[] = OpenStackNovaRole::getProjectRoleByName( $rolename, $this ); } $this->userrole = OpenStackNovaRole::getProjectRoleByName( self::$userrolename, $this ); // fetch the associated posix project group (project-$projectname) $this->fetchProjectGroup(); $this->fetchServiceGroups(); $this->loaded = true; } function fetchServiceGroups() { - global $wgAuth; global $wgOpenStackManagerLDAPServiceGroupBaseDN; - $result = LdapAuthenticationPlugin::ldap_search( $wgAuth->ldapconn, + $ldap = LdapAuthenticationPlugin::getInstance(); + $result = LdapAuthenticationPlugin::ldap_search( $ldap->ldapconn, $wgOpenStackManagerLDAPServiceGroupBaseDN, '(objectclass=groupofnames)' ); if ( $result ) { $this->serviceGroups = array(); - $groupList = LdapAuthenticationPlugin::ldap_get_entries( $wgAuth->ldapconn, $result ); + $groupList = LdapAuthenticationPlugin::ldap_get_entries( $ldap->ldapconn, $result ); if ( isset( $groupList ) ) { array_shift( $groupList ); foreach ( $groupList as $groupEntry ) { # Now we have every group. Check if this one belongs to us. $matchstring = $this->projectname . "."; if ( strpos($groupEntry['cn'][0], $matchstring) === 0 ) { $this->serviceGroups[] = new OpenStackNovaServiceGroup( $groupEntry['cn'][0], $this ); } } } } else { $this->serviceGroups = array(); } $serviceUserBaseDN = "ou=people" . "," . $wgOpenStackManagerLDAPServiceGroupBaseDN; - $result = LdapAuthenticationPlugin::ldap_search( $wgAuth->ldapconn, + $result = LdapAuthenticationPlugin::ldap_search( $ldap->ldapconn, $serviceUserBaseDN, '(objectclass=person)' ); if ( $result ) { $this->serviceUsers = array(); - $userList = LdapAuthenticationPlugin::ldap_get_entries( $wgAuth->ldapconn, $result ); + $userList = LdapAuthenticationPlugin::ldap_get_entries( $ldap->ldapconn, $result ); if ( isset( $userList ) ) { array_shift( $userList ); foreach ( $userList as $userEntry ) { # Now we have every user. Check if this one belongs to us. $matchstring = $this->projectname . "."; if ( strpos($userEntry['cn'][0], $matchstring) === 0 ) { - $wgAuth->printDebug( "adding " . $userEntry['cn'][0], NONSENSITIVE ); + $ldap->printDebug( "adding " . $userEntry['cn'][0], NONSENSITIVE ); $this->serviceUsers[] = $userEntry['cn'][0]; } } } } else { $this->serviceUsers = array(); } } /** * Initializes the corresponding project group object for this project. * If the ProjectGroup can't be loaded OR if the existing ProjectGroup * is a virtual static group, then the ProjectGroup will be recreated * from scratch and the members will be synced from this Project's * list of members. * * @return void */ function fetchProjectGroup() { - global $wgAuth; $this->projectGroup = new OpenStackNovaProjectGroup( $this->projectname ); // If we couldn't find an corresponding Project Group, // then we should create one now. if ( !$this->projectGroup->loaded ) { - $wgAuth->printDebug( $this->projectGroup->getProjectGroupName() . " does not exist. Creating it.", NONSENSITIVE ); + $ldap = LdapAuthenticationPlugin::getInstance(); + $ldap->printDebug( $this->projectGroup->getProjectGroupName() . " does not exist. Creating it.", NONSENSITIVE ); $createSuccess = OpenStackNovaProjectGroup::createProjectGroup( $this->projectname ); // Aaaaand if we successfully created the group, then finally sync the members from this project now. if ( $createSuccess ) { $this->projectGroup = new OpenStackNovaProjectGroup( $this->projectname ); $this->syncProjectGroupMembers(); } } } /** * @return string */ function getProjectName() { return $this->getName(); } /** * Returns the corresponding ProjectGroup for this Project. * If necessary, the ProjectGroup will be loaded from LDAP. * * @return OpenStackNovaProjectGroup */ function getProjectGroup() { if ( !$this->loaded ) { $this->fetchProjectGroup(); } return $this->projectGroup; } /** * Return all roles for this project * @return array */ function getRoles() { return $this->roles; } /** * Return all service groups for this project * @return array */ function getServiceGroups() { return $this->serviceGroups; } /** * Return all service users for this project * @return array */ function getServiceUsers() { return $this->serviceUsers; } /** * Fill $this->members. * * $this->members uses the uid as index and the name as value. * * @return array */ function loadMembers() { global $wgMemc; $key = wfMemcKey( 'openstackmanager', 'projectuidsandmembers', $this->projectname ); $this->members = $wgMemc->get( $key ); if ( is_array( $this->members ) ) { return; } $controller = OpenstackNovaProject::getController(); $this->members = $controller->getUsersInProject( $this->projectid ); $wgMemc->set( $key, $this->members, '3600' ); } /** * Return UIDs for users who are a member of this project * * We need this for managing things related to sudoers; generating * the list is expensive and caching it here is a big speedup. * * @return array */ function getMemberUids() { $this->loadMembers(); return array_keys( $this->members ); } /** * Return all users who are a member of this project * * @return array */ function getMembers() { $this->loadMembers(); return array_values( $this->members ); } /** * Return Ids of each user who is a member of this project * * @return array */ function getMemberIds() { $this->loadMembers(); return array_keys( $this->members ); } function memberForUid( $uid ) { $this->loadMembers(); return $this->members[$uid]; } function uidForMember( $username ) { $this->loadMembers(); foreach ( $this->members as $id => $name ) { if ( $username == $name ) { return $id; } } return ""; } /** * Returns an array of all member DNs that belong to this project. * * @return array */ function getMemberDNs() { global $wgLDAPUserBaseDNs; $memberids = $this->getMemberIDs(); $memberDNs = array(); $dnstring = implode( ",", $wgLDAPUserBaseDNs ); foreach ( $memberids as $member ) { $memberDNs[] = "uid=$member,$dnstring"; } return $memberDNs; } function getProjectDN() { if ( !$this->projectDN ) { $this->loadProjectName(); } return $this->projectDN; } function getSudoersDN() { return 'ou=sudoers,' . $this->getProjectDN(); } /** * Inform role objects that membership has changed and they * need to refresh their caches. * * @param $user OpenStackNovaUser */ function deleteRoleCaches( $username ) { $user = new OpenStackNovaUser( $username ); if ( $this->roles ) { foreach ( $this->roles as $role ) { $role->deleteMemcKeys( $user ); } } $this->userrole->deleteMemcKeys( $user ); } /** * Remove a member from the project based on username * * @param $username string * @return bool */ function deleteMember( $username ) { - global $wgAuth; global $wgMemc; + $ldap = LdapAuthenticationPlugin::getInstance(); $key = wfMemcKey( 'openstackmanager', 'projectuidsandmembers', $this->projectname ); $wgMemc->delete( $key ); if ( $this->userrole->deleteMember( $username ) ) { $this->projectGroup->deleteMember( $username ); foreach ( $this->roles as $role ) { $role->deleteMember( $username ); # @todo Find a way to fail gracefully if role member # deletion fails } $sudoers = OpenStackNovaSudoer::getAllSudoersByProject( $this->getProjectName() ); foreach ( $sudoers as $sudoer ) { $success = $sudoer->deleteUser( $username ); if ( $success ) { - $wgAuth->printDebug( "Successfully removed $username from " . $sudoer->getSudoerName(), NONSENSITIVE ); + $ldap->printDebug( "Successfully removed $username from " . $sudoer->getSudoerName(), NONSENSITIVE ); } else { - $wgAuth->printDebug( "Failed to remove $username from " . $sudoer->getSudoerName(), NONSENSITIVE ); + $ldap->printDebug( "Failed to remove $username from " . $sudoer->getSudoerName(), NONSENSITIVE ); } } - $wgAuth->printDebug( "Successfully removed $user->userDN from $this->projectname", NONSENSITIVE ); + $ldap->printDebug( "Successfully removed $user->userDN from $this->projectname", NONSENSITIVE ); $this->deleteRoleCaches( $username ); $this->editArticle(); return true; } else { - $wgAuth->printDebug( "Failed to remove $username from $this->projectname: " . ldap_error($wgAuth->ldapconn), NONSENSITIVE ); + $ldap->printDebug( "Failed to remove $username from $this->projectname: " . ldap_error($ldap->ldapconn), NONSENSITIVE ); return false; } } /** * Add a service group to this project * * @param $groupname string * @return bool */ function addServiceGroup( $groupName, $initialUser ) { - global $wgAuth; - $group = OpenStackNovaServiceGroup::createServiceGroup( $groupName, $this, $initialUser ); if ( ! $group ) { - $wgAuth->printDebug( "Failed to create service group $groupName", NONSENSITIVE ); + $ldap = LdapAuthenticationPlugin::getInstance(); + $ldap->printDebug( "Failed to create service group $groupName", NONSENSITIVE ); return false; } $this->fetchServiceGroups(); return true; } /** * Remove a service group from the project * * @param $groupName string * @return bool */ function deleteServiceGroup( $groupName ) { - global $wgAuth; - $success = OpenStackNovaServiceGroup::deleteServiceGroup( $groupName, $this ); $this->fetchServiceGroups(); return $success; } /** * Add a member to this project based on username * * @param $username string * @return bool */ function addMember( $username ) { - global $wgAuth; global $wgMemc; + $ldap = LdapAuthenticationPlugin::getInstance(); $key = wfMemcKey( 'openstackmanager', 'projectuidsandmembers', $this->projectname ); $wgMemc->delete( $key ); if ( !$this->userrole ) { $this->userrole = OpenStackNovaRole::getProjectRoleByName( self::$userrolename, $this ); } if ( $this->userrole->addMember( $username ) ) { // If we successfully added the member to this Project, then // also add the member to the corresponding ProjectGroup. $this->projectGroup->addMember( $username ); $this->deleteRoleCaches( $username ); - $wgAuth->printDebug( "Successfully added $username to $this->projectname", NONSENSITIVE ); + $ldap->printDebug( "Successfully added $username to $this->projectname", NONSENSITIVE ); $this->editArticle(); return true; } else { - $wgAuth->printDebug( "Failed to add $username to $this->projectname", NONSENSITIVE ); + $ldap->printDebug( "Failed to add $username to $this->projectname", NONSENSITIVE ); return false; } } /** * Compares members between this Project and its * corresponding ProjectGroup. If they differ, * Then the entire member list for the ProjectGroup * will be overwritten with this list of members. * * @return int -1 on failure, 0 on nochange, and 1 on a successful sync */ function syncProjectGroupMembers() { $failure = -1; $nochange = 0; $synced = 1; // These both return a sorted array of Member DNs $projectMemberDNs = $this->getMemberDNs(); $projectGroupMemberDNs = $this->projectGroup->getMemberDNs(); // These two arrays should be exactly the same, // so comparing them using == should work. // If they are not the same, then modify the // project group member list so that it exactly // matches the list from the project. if ( $projectMemberDNs != $projectGroupMemberDNs ) { $sync_success = $this->projectGroup->setMembers( $projectMemberDNs ); $retval = $sync_success == true ? $synced : $failure; } else { $retval = $nochange; } return $retval; } /** * Return a project by its project name. Returns null if the project does not exist. * This function is terrible and should be used sparingly * * @static * @param $projectname * @return null|OpenStackNovaProject */ static function getProjectByName( $projectname ) { $projects = self::getAllProjects(); foreach ( $projects as $project ) { if ( $project->getProjectName() == $projectname ) { return $project; } } return null; } /** * Return a project by its project id. Returns null if the project does not exist. * * @static * @param $projectname * @return null|OpenStackNovaProject */ static function getProjectById( $projectid ) { if ( isset( self::$projectCache[ $projectid ] ) ) { return self::$projectCache[ $projectid ]; } $project = new OpenStackNovaProject( $projectid ); if ( $project ) { if ( count( self::$projectCache ) >= self::$projectCacheMaxSize ) { array_shift( self::$projectCache ); } self::$projectCache[ $projectid ] = $project; return $project; } else { return null; } } static function getController() { # Because of weird issues in the Keystone auth model, we can't # really modify project info as the current user. For now # we're doing this with a global all-powerful account, # and relying on the GUI code to ensure that we're allowed :( # # In particular, keystone doesn't have any user roll which # allows editing membership of some projects but not others. global $wgOpenStackManagerLDAPUsername; $userLDAP = new OpenStackNovaUser( $wgOpenStackManagerLDAPUsername ); return OpenStackNovaController::newFromUser( $userLDAP ); } static function getProjectsByName( $projectnames ) { $projects = array(); foreach ( $projectnames as $projectname ) { $project = self::getProjectByName( $projectname ); if ( $project ) { $projects[] = $project; } } return $projects; } static function getProjectsById( $projectids ) { $projects = array(); foreach ( $projectids as $projectid ) { $project = self::getProjectById( $projectid ); if ( $project ) { $projects[] = $project; } } return $projects; } /** * Get all project names * * @return string[] */ static function getAllProjectNames() { $projects = self::getAllProjects(); $names = array(); foreach ( $projects as $project ) { $names[] = $project->getName(); } return $names; } /** * Get the list of projects from Keystone. * * @static * @return array of projectid => projectname */ static function getProjectList() { global $wgMemc; $key = wfMemcKey( 'openstackmanager', 'projectlist' ); $projectList = $wgMemc->get( $key ); if ( is_array( $projectList ) ) { return $projectList; } $controller = OpenstackNovaProject::getController(); $projectList = $controller->getProjects(); $wgMemc->set( $key, $projectList, '3600' ); return $projectList; } /** * Return all existing projects. Returns an empty array if no projects exist. This function * lazy loads the projects. Objects will be returned unloaded. If you wish to receive more * than just the project's name, you'll need to call the project's fetchProjectInfo() function. * * @static * @return OpenStackNovaProject[] */ static function getAllProjects() { - global $wgAuth; - $projects = array(); foreach( OpenStackNovaProject::getProjectList() as $id => $name ) { $project = new OpenStackNovaProject( $id, false ); $project->setName( $name ); $projects[] = $project; } sort( $projects ); return $projects; } /** * Create a new project based on project name. This function will also create * all roles needed by the project. * * @static * @param $projectname * @return OpenStackNovaProject */ static function createProject( $projectname ) { - global $wgAuth, $wgMemc; + global $wgMemc; global $wgOpenStackManagerLDAPUser; global $wgOpenStackManagerLDAPProjectBaseDN; + $ldap = LdapAuthenticationPlugin::getInstance(); $controller = OpenstackNovaProject::getController(); $newProjectId = $controller->createProject( $projectname ); $wgMemc->delete( wfMemcKey( 'openstackmanager', 'projectlist' ) ); if ( $newProjectId ) { # We need to create the Ldap project as well, so it's there to contain sudoers &c. OpenStackNovaLdapConnection::connect(); $ldapproject = array(); $ldapproject['objectclass'][] = 'extensibleobject'; $ldapproject['objectclass'][] = 'groupofnames'; $ldapproject['cn'] = $projectname; $ldapproject['member'] = $wgOpenStackManagerLDAPUser; $projectdn = 'cn=' . $projectname . ',' . $wgOpenStackManagerLDAPProjectBaseDN; - $success = LdapAuthenticationPlugin::ldap_add( $wgAuth->ldapconn, $projectdn, $ldapproject ); + $success = LdapAuthenticationPlugin::ldap_add( $ldap->ldapconn, $projectdn, $ldapproject ); if ( !$success ) { - $wgAuth->printDebug( "Creation of ldap project container failed for $projectname", NONSENSITIVE ); + $ldap->printDebug( "Creation of ldap project container failed for $projectname", NONSENSITIVE ); } - $wgAuth->printDebug( "Added ldap project container $projectname", NONSENSITIVE ); + $ldap->printDebug( "Added ldap project container $projectname", NONSENSITIVE ); $project = new OpenstackNovaProject( $newProjectId, false ); $projectdn = $project->getProjectDN(); $sudoerOU = array(); $sudoerOU['objectclass'][] = 'organizationalunit'; $sudoerOU['ou'] = 'sudooers'; $sudoerOUdn = 'ou=sudoers,' . $projectdn; - LdapAuthenticationPlugin::ldap_add( $wgAuth->ldapconn, $sudoerOUdn, $sudoerOU ); + LdapAuthenticationPlugin::ldap_add( $ldap->ldapconn, $sudoerOUdn, $sudoerOU ); # TODO: If sudoerOU creation fails we need to be able to fail gracefully // Now that we've created the Project, if we // are supposed to use a corresponding Project Group // to manage posix group permissions, do so now. OpenStackNovaProjectGroup::createProjectGroup( $projectname ); # TODO: If project group creation fails we need to be able to fail gracefully // Create two default, permissive sudo policies. First, // allow sudo (as root) for all members... $projectGroup = "%" . $project->getProjectGroup()->getProjectGroupName(); if ( OpenStackNovaSudoer::createSudoer( 'default-sudo', $projectname, array( $projectGroup ), array(), array( 'ALL' ), array( '!authenticate' ) ) ) { - $wgAuth->printDebug( "Successfully created default sudo policy for $projectname", NONSENSITIVE ); + $ldap->printDebug( "Successfully created default sudo policy for $projectname", NONSENSITIVE ); } // Now, allow all project members to sudo to all other users. $projectGroup = "%" . $project->getProjectGroup()->getProjectGroupName(); if ( OpenStackNovaSudoer::createSudoer( 'default-sudo-as', $projectname, array( $projectGroup ), array( "$projectGroup" ), array( 'ALL' ), array( '!authenticate' ) ) ) { - $wgAuth->printDebug( "Successfully created default sudo-as policy for $projectname", NONSENSITIVE ); + $ldap->printDebug( "Successfully created default sudo-as policy for $projectname", NONSENSITIVE ); } OpenStackNovaProject::createServiceGroupOUs( $projectname ); } else { - $wgAuth->printDebug( "Failed to add project $projectname", NONSENSITIVE ); + $ldap->printDebug( "Failed to add project $projectname", NONSENSITIVE ); return null; } $project->fetchProjectInfo(); return $project; } /** * Add the top-level entry for Service Groups to this project. * This is in a separate function so we can call it for old entries * for reverse-compatibility * * @param $projectname String * @return bool */ static function createServiceGroupOUs( $projectname ) { - global $wgAuth; global $wgOpenStackManagerLDAPProjectBaseDN; + $ldap = LdapAuthenticationPlugin::getInstance(); + // Create ou for service groups $groups = array(); $groups['objectclass'][] = 'organizationalunit'; $groups['ou'] = 'groups'; $groupsdn = 'ou=' . $groups['ou'] . ',' . 'cn=' . $projectname . ',' . $wgOpenStackManagerLDAPProjectBaseDN; - $success = LdapAuthenticationPlugin::ldap_add( $wgAuth->ldapconn, $groupsdn, $groups ); + $success = LdapAuthenticationPlugin::ldap_add( $ldap->ldapconn, $groupsdn, $groups ); if ( !$success ) { - $wgAuth->printDebug( "Failed to create service group ou for project $projectname", NONSENSITIVE ); + $ldap->printDebug( "Failed to create service group ou for project $projectname", NONSENSITIVE ); return false; } // Create ou for service users $users = array(); $users['objectclass'][] = 'organizationalunit'; $users['ou'] = 'people'; $usersdn = 'ou=' . $users['ou'] . ',' . 'cn=' . $projectname . ',' . $wgOpenStackManagerLDAPProjectBaseDN; - $success = LdapAuthenticationPlugin::ldap_add( $wgAuth->ldapconn, $usersdn, $users ); + $success = LdapAuthenticationPlugin::ldap_add( $ldap->ldapconn, $usersdn, $users ); if ( !$success ) { - $wgAuth->printDebug( "Failed to create service user ou for project $projectname", NONSENSITIVE ); + $ldap->printDebug( "Failed to create service user ou for project $projectname", NONSENSITIVE ); return false; } return true; } /** * Remove the top-level entry for Service Groups to this project. * * @param $projectname String * @return bool */ function deleteServiceGroupOUs() { - global $wgAuth; global $wgOpenStackManagerLDAPProjectBaseDN; + $ldap = LdapAuthenticationPlugin::getInstance(); + $groups = array(); $groups['objectclass'][] = 'organizationalunit'; $groups['ou'] = 'groups'; $groupsdn = 'ou=' . $groups['ou'] . ',' . 'cn=' . $this->projectname . ',' . $wgOpenStackManagerLDAPProjectBaseDN; - $success = LdapAuthenticationPlugin::ldap_delete( $wgAuth->ldapconn, $groupsdn ); + $success = LdapAuthenticationPlugin::ldap_delete( $ldap->ldapconn, $groupsdn ); if ( !$success ) { - $wgAuth->printDebug( "Failed to delete service group ou for project $this->projectname", NONSENSITIVE ); + $ldap->printDebug( "Failed to delete service group ou for project $this->projectname", NONSENSITIVE ); return false; } $users = array(); $users['objectclass'][] = 'organizationalunit'; $users['ou'] = 'people'; $usersdn = 'ou=' . $users['ou'] . ',' . 'cn=' . $this->projectname . ',' . $wgOpenStackManagerLDAPProjectBaseDN; - $success = LdapAuthenticationPlugin::ldap_delete( $wgAuth->ldapconn, $usersdn ); + $success = LdapAuthenticationPlugin::ldap_delete( $ldap->ldapconn, $usersdn ); if ( !$success ) { - $wgAuth->printDebug( "Failed to delete service user ou for project $this->projectname", NONSENSITIVE ); + $ldap->printDebug( "Failed to delete service user ou for project $this->projectname", NONSENSITIVE ); return false; } return true; } /** * Deletes a project based on project id. This function will also delete all roles * associated with the project. * * @param $projectid String * @return bool */ static function deleteProject( $projectid ) { - global $wgAuth, $wgMemc; + global $wgMemc; $project = new OpenStackNovaProject( $projectid ); if ( ! $project ) { return false; } $projectname = $project->getName(); + $ldap = LdapAuthenticationPlugin::getInstance(); OpenStackNovaLdapConnection::connect(); OpenStackNovaProjectGroup::deleteProjectGroup( $project->getProjectName() ); # Projects have a sudo OU and sudoers entries below that OU, we must delete them first $sudoers = OpenStackNovaSudoer::getAllSudoersByProject( $project->getProjectName() ); foreach ( $sudoers as $sudoer ) { $success = OpenStackNovaSudoer::deleteSudoer( $sudoer->getSudoerName(), $project->getProjectName() ); if ( $success ){ - $wgAuth->printDebug( "Successfully deleted sudoer " . $sudoer->getSudoerName(), NONSENSITIVE ); + $ldap->printDebug( "Successfully deleted sudoer " . $sudoer->getSudoerName(), NONSENSITIVE ); } else { - $wgAuth->printDebug( "Failed to delete sudoer " . $sudoer->getSudoerName(), NONSENSITIVE ); + $ldap->printDebug( "Failed to delete sudoer " . $sudoer->getSudoerName(), NONSENSITIVE ); } } - $success = LdapAuthenticationPlugin::ldap_delete( $wgAuth->ldapconn, $project->getSudoersDN() ); + $success = LdapAuthenticationPlugin::ldap_delete( $ldap->ldapconn, $project->getSudoersDN() ); if ( $success ) { - $wgAuth->printDebug( "Successfully deleted sudoers OU " . $project->getSudoersDN(), NONSENSITIVE ); + $ldap->printDebug( "Successfully deleted sudoers OU " . $project->getSudoersDN(), NONSENSITIVE ); } else { - $wgAuth->printDebug( "Failed to delete sudoers OU " . $project->getSudoersDN(), NONSENSITIVE ); + $ldap->printDebug( "Failed to delete sudoers OU " . $project->getSudoersDN(), NONSENSITIVE ); } # And, we need to clean up service groups. $servicegroups = $project->getServiceGroups(); foreach ( $servicegroups as $group ) { $groupName = $group->groupName; $success = OpenStackNovaServiceGroup::deleteServiceGroup( $groupName, $project ); if ( $success ){ - $wgAuth->printDebug( "Successfully deleted service group " . $groupName, NONSENSITIVE ); + $ldap->printDebug( "Successfully deleted service group " . $groupName, NONSENSITIVE ); } else { - $wgAuth->printDebug( "Failed to delete service group " . $groupName, NONSENSITIVE ); + $ldap->printDebug( "Failed to delete service group " . $groupName, NONSENSITIVE ); } } $project->deleteServiceGroupOUs(); $dn = $project->projectDN; - $success = LdapAuthenticationPlugin::ldap_delete( $wgAuth->ldapconn, $dn ); + $success = LdapAuthenticationPlugin::ldap_delete( $ldap->ldapconn, $dn ); if ( !$success ) { - $wgAuth->printDebug( "Failed to delete project LDAP container $dn", NONSENSITIVE ); + $ldap->printDebug( "Failed to delete project LDAP container $dn", NONSENSITIVE ); } $controller = OpenstackNovaProject::getController(); $success = $controller->deleteProject( $projectid ); $wgMemc->delete( wfMemcKey( 'openstackmanager', 'projectlist' ) ); if ( $success ) { - $wgAuth->printDebug( "Successfully deleted project", NONSENSITIVE ); + $ldap->printDebug( "Successfully deleted project", NONSENSITIVE ); return true; } else { - $wgAuth->printDebug( "Failed to delete project", NONSENSITIVE ); + $ldap->printDebug( "Failed to delete project", NONSENSITIVE ); return false; } } function editArticle() { global $wgOpenStackManagerCreateProjectSALPages, $wgOpenStackManagerProjectNamespace, $wgOpenStackManagerBastionProjectName; if ( ! OpenStackNovaArticle::canCreatePages() ) { return; } $format = <<getMembers(); $members = array(); // FIXME! This was too slow on the bastion project, which users get added to automatically. // See https://phabricator.wikimedia.org/T114229 for details. if ( $this->getProjectName() !== $wgOpenStackManagerBastionProjectName ) { foreach ( $rawmembers as $member ) { $members[] = 'User:' . $member; } } $admins = array(); # All roles have elevated privileges, count them all as admins foreach ( $this->getRoles() as $role ) { $rawadmins = $role->getMembers(); foreach ( $rawadmins as $admin ) { $admins[] = 'User:' . $admin; } } $text = sprintf( $format, $this->getProjectName(), implode( ",\n", $admins ), implode( ",\n", $members ) ); OpenStackNovaArticle::editArticle( $this->getProjectName(), $text, $wgOpenStackManagerProjectNamespace ); if ( $wgOpenStackManagerCreateProjectSALPages ) { $pagename = $this->getProjectName() . "/SAL"; $id = Title::newFromText( $pagename, $wgOpenStackManagerProjectNamespace )->getArticleId(); $article = Article::newFromId( $id ); $content = ''; if ( $article ) { $content = $article->getContent( Revision::RAW ); } $text = "{{SAL|Project Name=" . $this->getProjectName() . "}}"; if ( !strstr( $content, $text ) ) { OpenStackNovaArticle::editArticle( $pagename, $text, $wgOpenStackManagerProjectNamespace ); } } } function deleteArticle() { global $wgOpenStackManagerProjectNamespace; OpenStackNovaArticle::deleteArticle( $this->getProjectName(), $wgOpenStackManagerProjectNamespace ); } /** * Get service user homedir setting for project. * * This is stored as an 'info' setting in ldap: * * Note: This setting is obsolete and can no longer be changed. It's preserved as legacy * for a small number of projects who rely on it being set. * * info: homedirpattern= * * @return string */ function getServiceGroupHomedirPattern() { global $wgOpenStackManagerServiceGroupHomedirPattern; - global $wgOpenStackManagerLDAPProjectBaseDN, $wgAuth; + global $wgOpenStackManagerLDAPProjectBaseDN; $pattern = $wgOpenStackManagerServiceGroupHomedirPattern; - $result = LdapAuthenticationPlugin::ldap_search( $wgAuth->ldapconn, $wgOpenStackManagerLDAPProjectBaseDN, + $ldap = LdapAuthenticationPlugin::getInstance(); + $result = LdapAuthenticationPlugin::ldap_search( $ldap->ldapconn, $wgOpenStackManagerLDAPProjectBaseDN, '(&(cn=' . $this->getProjectName() . ')(objectclass=groupofnames))' ); - $projectInfo = LdapAuthenticationPlugin::ldap_get_entries( $wgAuth->ldapconn, $result ); + $projectInfo = LdapAuthenticationPlugin::ldap_get_entries( $ldap->ldapconn, $result ); if ( isset( $projectInfo[0]['info'] ) ) { $infos = $projectInfo[0]['info']; // first member is a count. array_shift( $infos ); foreach ( $infos as $info ) { $substrings=explode( '=', $info ); if ( ( count( $substrings ) == 2 ) and ( $substrings[0] == 'servicegrouphomedirpattern' ) ) { $pattern = $substrings[1]; break; } } } return $pattern; } } diff --git a/nova/OpenStackNovaProjectGroup.php b/nova/OpenStackNovaProjectGroup.php index 479a79d..70bfa71 100644 --- a/nova/OpenStackNovaProjectGroup.php +++ b/nova/OpenStackNovaProjectGroup.php @@ -1,294 +1,291 @@ projectName = $projectName; if ( $load ) { OpenStackNovaLdapConnection::connect(); $this->fetchProjectGroupInfo(); } else { $this->loaded = false; } } /** * Fetch the project group from LDAP and initialize the object * @return void */ function fetchProjectGroupInfo( $refresh=true ) { - global $wgAuth; global $wgOpenStackManagerLDAPProjectGroupBaseDN; if ( $this->loaded and !$refresh ) { return; } - $result = LdapAuthenticationPlugin::ldap_search( $wgAuth->ldapconn, $wgOpenStackManagerLDAPProjectGroupBaseDN, + $ldap = LdapAuthenticationPlugin::getInstance(); + $result = LdapAuthenticationPlugin::ldap_search( $ldap->ldapconn, $wgOpenStackManagerLDAPProjectGroupBaseDN, '(&(cn=' . $this->getProjectGroupName() . ')(objectclass=groupofnames))' ); - $this->projectGroupInfo = LdapAuthenticationPlugin::ldap_get_entries( $wgAuth->ldapconn, $result ); + $this->projectGroupInfo = LdapAuthenticationPlugin::ldap_get_entries( $ldap->ldapconn, $result ); if ( !isset( $this->projectGroupInfo[0] ) ) { $this->loaded = false; return; } $this->projectGroupDN = $this->projectGroupInfo[0]['dn']; $this->loaded = true; } /** * Returns the project group name, which is * just the corresponding project name prefixed * by self::$prefix. * * @return string */ function getProjectGroupName() { return self::$prefix . $this->projectName; } /** * Return all users who are a member of this project * * @return array */ function getMembers() { - global $wgAuth; global $wgOpenStackManagerLDAPDomain; $members = array(); if ( isset( $this->projectGroupInfo[0]['member'] ) ) { + $ldap = LdapAuthenticationPlugin::getInstance(); $memberdns = $this->projectGroupInfo[0]['member']; array_shift( $memberdns ); foreach ( $memberdns as $memberdn ) { - $searchattr = $wgAuth->getConf( 'SearchAttribute', $wgOpenStackManagerLDAPDomain ); + $searchattr = $ldap->getConf( 'SearchAttribute', $wgOpenStackManagerLDAPDomain ); if ( $searchattr ) { // We need to look up the search attr from the user entry // this is expensive, but must be done. // TODO: memcache this - $userInfo = $wgAuth->getUserInfoStateless( $memberdn ); + $userInfo = $ldap->getUserInfoStateless( $memberdn ); $members[] = $userInfo[0][$searchattr][0]; } else { $member = explode( '=', $memberdn ); $member = explode( ',', $member[1] ); $member = $member[0]; $members[] = $member; } } } return $members; } /** * Returns an array of all member DNs that belong to this project group. * * @return array */ function getMemberDNs() { $memberDNs = array(); if ( isset( $this->projectGroupInfo[0]['member'] ) ) { $memberDNs = $this->projectGroupInfo[0]['member']; array_shift( $memberDNs ); sort( $memberDNs ); } return $memberDNs; } /** * Remove a member from the project group based on username * * @param $username string * @return bool */ function deleteMember( $username ) { - global $wgAuth; - if ( isset( $this->projectGroupInfo[0]['member'] ) ) { + $ldap = LdapAuthenticationPlugin::getInstance(); $members = $this->projectGroupInfo[0]['member']; array_shift( $members ); $user = new OpenStackNovaUser( $username ); if ( ! $user->userDN ) { - $wgAuth->printDebug( "Failed to find userDN for username $username in OpenStackNovaProjectGroup deleteMember.", NONSENSITIVE ); + $ldap->printDebug( "Failed to find userDN for username $username in OpenStackNovaProjectGroup deleteMember.", NONSENSITIVE ); return false; } $index = array_search( $user->userDN, $members ); if ( $index === false ) { - $wgAuth->printDebug( "Failed to find userDN " . $user->userDN . " in in ProjectGroup " . $this->projectGroupName . " member list", NONSENSITIVE ); + $ldap->printDebug( "Failed to find userDN " . $user->userDN . " in in ProjectGroup " . $this->projectGroupName . " member list", NONSENSITIVE ); return false; } unset( $members[$index] ); $values = array(); $values['member'] = array(); foreach ( $members as $member ) { $values['member'][] = $member; } - $success = LdapAuthenticationPlugin::ldap_modify( $wgAuth->ldapconn, $this->projectGroupDN, $values ); + $success = LdapAuthenticationPlugin::ldap_modify( $ldap->ldapconn, $this->projectGroupDN, $values ); if ( $success ) { $this->fetchProjectGroupInfo( true ); - $wgAuth->printDebug( "Successfully removed $user->userDN from $this->projectGroupDN", NONSENSITIVE ); + $ldap->printDebug( "Successfully removed $user->userDN from $this->projectGroupDN", NONSENSITIVE ); return true; } else { - $wgAuth->printDebug( "Failed to remove $user->userDN from $this->projectGroupDN: " . ldap_error($wgAuth->ldapconn), NONSENSITIVE ); + $ldap->printDebug( "Failed to remove $user->userDN from $this->projectGroupDN: " . ldap_error($ldap->ldapconn), NONSENSITIVE ); return false; } } else { return false; } } /** * Takes an array of memberDNs and saves it to the project group in LDAP. * * @param $memberDNs array as returned by getMemberDNs(). * @return bool */ function setMembers( $memberDNs ) { - global $wgAuth; - + $ldap = LdapAuthenticationPlugin::getInstance(); $values = array( 'member' => $memberDNs ); - $success = LdapAuthenticationPlugin::ldap_modify( $wgAuth->ldapconn, $this->projectGroupDN, $values ); + $success = LdapAuthenticationPlugin::ldap_modify( $ldap->ldapconn, $this->projectGroupDN, $values ); if ( $success ) { // reload the ProjectGroup from LDAP. $this->fetchProjectGroupInfo( true ); - $wgAuth->printDebug( "Successfully set " . count( $memberDNs ) . " members to $this->projectGroupDN", NONSENSITIVE ); + $ldap->printDebug( "Successfully set " . count( $memberDNs ) . " members to $this->projectGroupDN", NONSENSITIVE ); } else { - $wgAuth->printDebug( "Failed to set " . count( $memberDNs ) . " members to $this->projectGroupDN: " . ldap_error( $wgAuth->ldapconn ) . ". [" . join( ";", $memberDNs ) . "]", NONSENSITIVE ); + $ldap->printDebug( "Failed to set " . count( $memberDNs ) . " members to $this->projectGroupDN: " . ldap_error( $ldap->ldapconn ) . ". [" . join( ";", $memberDNs ) . "]", NONSENSITIVE ); } return $success; } /** * Add a member to this project based on username * * @param $username string * @return bool */ function addMember( $username ) { - global $wgAuth; - + $ldap = LdapAuthenticationPlugin::getInstance(); $members = array(); if ( isset( $this->projectGroupInfo[0]['member'] ) ) { $members = $this->projectGroupInfo[0]['member']; array_shift( $members ); } $user = new OpenStackNovaUser( $username ); if ( ! $user->userDN ) { - $wgAuth->printDebug( "Failed to find userDN in addMember", NONSENSITIVE ); + $ldap->printDebug( "Failed to find userDN in addMember", NONSENSITIVE ); return false; } $members[] = $user->userDN; $values = array(); $values['member'] = $members; - $success = LdapAuthenticationPlugin::ldap_modify( $wgAuth->ldapconn, $this->projectGroupDN, $values ); + $success = LdapAuthenticationPlugin::ldap_modify( $ldap->ldapconn, $this->projectGroupDN, $values ); if ( $success ) { $this->fetchProjectGroupInfo( true ); - $wgAuth->printDebug( "Successfully added $user->userDN to $this->projectGroupDN", NONSENSITIVE ); + $ldap->printDebug( "Successfully added $user->userDN to $this->projectGroupDN", NONSENSITIVE ); return true; } else { - $wgAuth->printDebug( "Failed to add $user->userDN to $this->projectGroupDN: " . ldap_error($wgAuth->ldapconn), NONSENSITIVE ); + $ldap->printDebug( "Failed to add $user->userDN to $this->projectGroupDN: " . ldap_error($ldap->ldapconn), NONSENSITIVE ); return false; } } /** * Create a new project group based on project name. * * @static * @param $projectname * @return bool */ static function createProjectGroup( $projectname ) { - global $wgAuth; global $wgOpenStackManagerLDAPProjectGroupBaseDN; global $wgOpenStackManagerLDAPUsername; + $ldap = LdapAuthenticationPlugin::getInstance(); OpenStackNovaLdapConnection::connect(); $user = new OpenStackNovaUser( $wgOpenStackManagerLDAPUsername ); - if ( ! $user->userDN ) { - $wgAuth->printDebug( "Failed to find userDN in createProjectGroup", NONSENSITIVE ); - return false; - } + if ( ! $user->userDN ) { + $ldap->printDebug( "Failed to find userDN in createProjectGroup", NONSENSITIVE ); + return false; + } $projectGroupName = self::$prefix . $projectname; $projectGroup = array(); $projectGroup['member'][] = $user->userDN; $projectGroup['objectclass'][] = 'posixgroup'; $projectGroup['objectclass'][] = 'groupofnames'; $projectGroup['cn'] = $projectGroupName; - $projectGroup['gidnumber'] = OpenStackNovaUser::getNextIdNumber( $wgAuth, 'gidnumber' ); + $projectGroup['gidnumber'] = OpenStackNovaUser::getNextIdNumber( $ldap, 'gidnumber' ); $projectGroupDN = 'cn=' . $projectGroupName . ',' . $wgOpenStackManagerLDAPProjectGroupBaseDN; # TODO: If project group creation fails we need to be able to fail gracefully - $success = LdapAuthenticationPlugin::ldap_add( $wgAuth->ldapconn, $projectGroupDN, $projectGroup ); + $success = LdapAuthenticationPlugin::ldap_add( $ldap->ldapconn, $projectGroupDN, $projectGroup ); if ( $success ) { - $wgAuth->printDebug( "Successfully added project group $projectGroupName", NONSENSITIVE ); + $ldap->printDebug( "Successfully added project group $projectGroupName", NONSENSITIVE ); } else { - $wgAuth->printDebug( "Failed to add project group $projectGroupName: " . ldap_error( $wgAuth->ldapconn ), NONSENSITIVE ); - return false; + $ldap->printDebug( "Failed to add project group $projectGroupName: " . ldap_error( $ldap->ldapconn ), NONSENSITIVE ); + return false; } return $success; } /** * Deletes a project group based on project name. * * @param $projectname String * @return bool */ static function deleteProjectGroup( $projectname ) { - global $wgAuth; global $wgOpenStackManagerLDAPProjectGroupBaseDN; + $ldap = LdapAuthenticationPlugin::getInstance(); OpenStackNovaLdapConnection::connect(); $projectGroupName = self::$prefix . $projectname; $projectGroupDN = 'cn=' . $projectGroupName . ',' . $wgOpenStackManagerLDAPProjectGroupBaseDN; - $success = LdapAuthenticationPlugin::ldap_delete( $wgAuth->ldapconn, $projectGroupDN ); + $success = LdapAuthenticationPlugin::ldap_delete( $ldap->ldapconn, $projectGroupDN ); if ( $success ){ - $wgAuth->printDebug( "Successfully deleted project group $projectGroupDN", NONSENSITIVE ); + $ldap->printDebug( "Successfully deleted project group $projectGroupDN", NONSENSITIVE ); } else { - $wgAuth->printDebug( "Failed to delete project group $projectGroupDN: " . ldap_error( $wgAuth->ldapconn ), NONSENSITIVE ); + $ldap->printDebug( "Failed to delete project group $projectGroupDN: " . ldap_error( $ldap->ldapconn ), NONSENSITIVE ); } return $success; } } diff --git a/nova/OpenStackNovaPublicHost.php b/nova/OpenStackNovaPublicHost.php index beb74cd..4345981 100644 --- a/nova/OpenStackNovaPublicHost.php +++ b/nova/OpenStackNovaPublicHost.php @@ -1,65 +1,62 @@ domainCache = null; $this->ip = $ip; OpenStackNovaLdapConnection::connect(); $this->fetchHostInfo(); } /** * Fetch the host from LDAP and initialize the object * * @return void */ function fetchHostInfo() { - global $wgAuth; global $wgOpenStackManagerLDAPInstanceBaseDN; - $this->ip = $wgAuth->getLdapEscapedString( $this->ip ); - $result = LdapAuthenticationPlugin::ldap_search( $wgAuth->ldapconn, $wgOpenStackManagerLDAPInstanceBaseDN, '(dc=' . $this->ip . ')' ); - $this->hostInfo = LdapAuthenticationPlugin::ldap_get_entries( $wgAuth->ldapconn, $result ); + $ldap = LdapAuthenticationPlugin::getInstance(); + $this->ip = $ldap->getLdapEscapedString( $this->ip ); + $result = LdapAuthenticationPlugin::ldap_search( $ldap->ldapconn, $wgOpenStackManagerLDAPInstanceBaseDN, '(dc=' . $this->ip . ')' ); + $this->hostInfo = LdapAuthenticationPlugin::ldap_get_entries( $ldap->ldapconn, $result ); if ( $this->hostInfo["count"] == "0" ) { $this->hostInfo = null; } else { $this->hostDN = $this->hostInfo[0]['dn']; } } /** * Return the domain associated with this host * * @return OpenStackNovaDomain */ function getDomain() { - global $wgAuth; - if ( ! $this->domainCache ) { $this->domainCache = OpenStackNovaDomain::getDomainByHostIP( $this->ip ); if (! $this->domainCache ) { - $wgAuth->printDebug( "Looked up domain for ip $this->ip but domainCache is still empty.", NONSENSITIVE ); + $ldap = LdapAuthenticationPlugin::getInstance(); + $ldap->printDebug( "Looked up domain for ip $this->ip but domainCache is still empty.", NONSENSITIVE ); } } return $this->domainCache; } } diff --git a/nova/OpenStackNovaRole.php b/nova/OpenStackNovaRole.php index 292727b..e8c2495 100644 --- a/nova/OpenStackNovaRole.php +++ b/nova/OpenStackNovaRole.php @@ -1,212 +1,210 @@ roleid = $roleid; $this->project = $project; OpenStackNovaLdapConnection::connect(); $this->rolename = OpenStackNovaRole::getRoleNameForId( $this->roleid ); } /** * @return void */ function loadMembers() { global $wgMemc; $roleid = $this->roleid; $projectid = $this->project->getId(); $memberskey = wfMemcKey( 'openstackmanager', "role-members-$projectid", $roleid ); $this->members = $wgMemc->get( $memberskey ); if ( is_array ( $this->members ) ) { return; } # This caches assignment for all roles in project, not just this one. Should # save us a bit of time if we check another role later. $assignmentkey = wfMemcKey( 'openstackmanager', "role-assignments", $this->project->getId() ); $assignments = $wgMemc->get( $assignmentkey ); if ( ! is_array( $assignments ) ) { $controller = OpenstackNovaProject::getController(); $assignments = $controller->getRoleAssignmentsForProject( $projectid ); $wgMemc->set( $assignmentkey, $assignments, '3600' ); } $this->members = array(); if ( in_array( $this->roleid, array_keys( $assignments ) ) ) { foreach ($assignments[$this->roleid] as $userid ) { $this->members[] = $this->project->memberForUid( $userid ); } } $wgMemc->set( $memberskey, $this->members, '3600' ); } /** * @return string */ function getRoleName() { return $this->rolename; } /** * @return string */ function getRoleId() { return $this->roleid; } /** * @return array */ function getMembers() { $this->loadMembers(); return $this->members; } /** * @param $username * @return bool */ function deleteMember( $username ) { - global $wgAuth; - + $ldap = LdapAuthenticationPlugin::getInstance(); $user = new OpenStackNovaUser( $username ); $userid = $user->getUid(); $controller = OpenstackNovaProject::getController(); if ( $controller->revokeRoleForProjectAndUser( $this->roleid, $this->project->getId(), $userid ) ) { $user = new OpenStackNovaUser( $userid ); $this->deleteMemcKeys( $user ); - $wgAuth->printDebug( "Successfully removed $userid from role $this->rolename", NONSENSITIVE ); + $ldap->printDebug( "Successfully removed $userid from role $this->rolename", NONSENSITIVE ); return true; } else { - $wgAuth->printDebug( "Failed to remove $userid from role $this->rolename", NONSENSITIVE ); + $ldap->printDebug( "Failed to remove $userid from role $this->rolename", NONSENSITIVE ); return false; } } /** * @param $username * @return bool */ function addMember( $username ) { - global $wgAuth; - + $ldap = LdapAuthenticationPlugin::getInstance(); $user = new OpenStackNovaUser( $username ); $userid = $user->getUid(); - $controller = OpenstackNovaProject::getController(); + $controller = OpenstackNovaProject::getController(); if ( $controller->grantRoleForProjectAndUser( $this->roleid, $this->project->getId(), $userid ) ) { - $wgAuth->printDebug( "Successfully added $userid to $this->rolename", NONSENSITIVE ); + $ldap->printDebug( "Successfully added $userid to $this->rolename", NONSENSITIVE ); $user = new OpenStackNovaUser( $userid ); $this->deleteMemcKeys( $user ); return true; } else { - $wgAuth->printDebug( "Failed to add $userid to role $this->rolename", NONSENSITIVE ); + $ldap->printDebug( "Failed to add $userid to role $this->rolename", NONSENSITIVE ); return false; } } /** * @param $user * @return String string */ function deleteMemcKeys( $user ) { global $wgMemc; $projectid = $this->project->getId(); $role = $this->getRoleId(); $key = wfMemcKey( 'openstackmanager', "role-assignments", $projectid ); $wgMemc->delete( $key ); $username = $user->getUsername(); $key = wfMemcKey( 'openstackmanager', "fulltoken-$projectid", $username ); $wgMemc->delete( $key ); $key = wfMemcKey( 'openstackmanager', 'roles', $user->getUsername() ); $wgMemc->delete( $key ); $roleid = $this->roleid; $key = wfMemcKey( 'openstackmanager', "role-$roleid-members", $this->project->projectname ); $wgMemc->delete( $key ); $key = wfMemcKey( 'openstackmanager', "role-members-$projectid", $role ); $wgMemc->delete( $key ); } /** * @param $userLDAP * @return bool */ function userInRole( $userLDAP ) { $this->loadMembers(); if ( !$userLDAP ) { return false; } $member = explode( '=', $userLDAP ); $member = explode( ',', $member[1] ); $member = $member[0]; return in_array( $member, $this->members ); } /** * @static * @param $rolename * @param $project * @return null|OpenStackNovaRole */ static function getProjectRoleByName( $rolename, $project ) { $controller = OpenstackNovaProject::getController(); $globalrolelist = $controller->getKeystoneRoles(); foreach ( $globalrolelist as $id => $name ) { if ( $name == $rolename ) { return new OpenStackNovaRole( $id, $project ); } } return null; } /** * @static * @param $roleid * @return role name */ static function getRoleNameForId( $roleid ) { global $wgMemc; $key = wfMemcKey( 'openstackmanager', 'globalrolelist' ); $globalrolelist = $wgMemc->get( $key ); if ( ! is_array( $globalrolelist ) ) { $controller = OpenstackNovaProject::getController(); $globalrolelist = $controller->getKeystoneRoles(); # Roles basically never change, so this can be a long-lived cache $wgMemc->set( $key, $globalrolelist ); } return isset( $globalrolelist[$roleid] ) ? $globalrolelist[$roleid] : "unknown role"; } } diff --git a/nova/OpenStackNovaServiceGroup.php b/nova/OpenStackNovaServiceGroup.php index fdecd92..d1d18dc 100644 --- a/nova/OpenStackNovaServiceGroup.php +++ b/nova/OpenStackNovaServiceGroup.php @@ -1,428 +1,425 @@ project = $project; OpenStackNovaLdapConnection::connect(); $this->groupName = $groupName; $this->fetchGroupInfo( false ); } /** * @return void */ function fetchGroupInfo( $refreshCache = true ) { - global $wgAuth; global $wgOpenStackManagerLDAPServiceGroupBaseDN; global $wgMemc; # Load service group entry $dn = $wgOpenStackManagerLDAPServiceGroupBaseDN; $query = '(cn=' . $this->groupName . ')'; $key = wfMemcKey( 'openstackmanager', 'servicegroup', $this->groupName ); if ( $refreshCache ) { $wgMemc->delete( $key ); $groupInfo = null; } else { $groupInfo = $wgMemc->get( $key ); } if ( is_array( $groupInfo ) ) { $this->groupInfo = $groupInfo; } else { - $result = LdapAuthenticationPlugin::ldap_search( $wgAuth->ldapconn, $dn, $query ); - $this->groupInfo = LdapAuthenticationPlugin::ldap_get_entries( $wgAuth->ldapconn, $result ); + $ldap = LdapAuthenticationPlugin::getInstance(); + $result = LdapAuthenticationPlugin::ldap_search( $ldap->ldapconn, $dn, $query ); + $this->groupInfo = LdapAuthenticationPlugin::ldap_get_entries( $ldap->ldapconn, $result ); $wgMemc->set( $key, $this->groupInfo, 3600 * 24 ); } if ( $this->groupInfo['count'] != "0" ) { $this->groupDN = $this->groupInfo[0]['dn']; } $this->usersDN = "ou=people" . "," . $wgOpenStackManagerLDAPServiceGroupBaseDN; } /** * @return string */ function getGroupName() { return $this->groupName; } /** * @return string */ function getSpecialUserDN() { $userDN = "uid=" . $this->groupName . "," . $this->usersDN; return $userDN; } /** * @return array */ function getUidMembers() { - global $wgAuth; global $wgOpenStackManagerLDAPDomain; $members = array(); if ( isset( $this->groupInfo[0]['member'] ) ) { $memberdns = $this->groupInfo[0]['member']; if ( $memberdns['count'] === 0 ) { return $members; } array_shift( $memberdns ); foreach ( $memberdns as $memberdn ) { $info = explode( ',', $memberdn ); $info = explode( '=', $info[0] ); $attr = $info[0]; $member = $info[1]; if ( $attr === 'uid' ) { $members[] = $member; } else { - $userInfo = $wgAuth->getUserInfoStateless( $memberdn ); + $ldap = LdapAuthenticationPlugin::getInstance(); + $userInfo = $ldap->getUserInfoStateless( $memberdn ); $members[] = $userInfo[0]['uid'][0]; } } } return $members; } /** * @return array */ function getMembers() { - global $wgAuth; global $wgOpenStackManagerLDAPDomain; $members = array(); if ( isset( $this->groupInfo[0]['member'] ) ) { + $ldap = LdapAuthenticationPlugin::getInstance(); $memberdns = $this->groupInfo[0]['member']; array_shift( $memberdns ); foreach ( $memberdns as $memberdn ) { - $searchattr = $wgAuth->getConf( 'SearchAttribute', $wgOpenStackManagerLDAPDomain ); + $searchattr = $ldap->getConf( 'SearchAttribute', $wgOpenStackManagerLDAPDomain ); if ( $searchattr ) { - $userInfo = $wgAuth->getUserInfoStateless( $memberdn ); + $userInfo = $ldap->getUserInfoStateless( $memberdn ); $members[] = $userInfo[0][$searchattr][0]; } else { $member = explode( '=', $memberdn ); $member = explode( ',', $member[1] ); $member = $member[0]; $members[] = $member; } } } return $members; } /** * @param $username * @return bool */ function isMember( $username ) { return in_array( strtolower( $username ), array_map( 'strtolower', $this->getMembers() ) ); } /** * @param $username * @return bool */ function deleteMember( $username ) { - global $wgAuth; - if ( isset( $this->groupInfo[0]['member'] ) ) { + $ldap = LdapAuthenticationPlugin::getInstance(); $members = $this->groupInfo[0]['member']; array_shift( $members ); $user = new OpenStackNovaUser( $username ); if ( ! $user->userDN ) { - $wgAuth->printDebug( "Failed to find $username in deleteMember", NONSENSITIVE ); + $ldap->printDebug( "Failed to find $username in deleteMember", NONSENSITIVE ); return false; } $index = array_search( $user->userDN, $members ); if ( $index === false ) { - $wgAuth->printDebug( "Failed to find userDN in member list", NONSENSITIVE ); + $ldap->printDebug( "Failed to find userDN in member list", NONSENSITIVE ); return false; } unset( $members[$index] ); $values = array(); $values['member'] = array(); foreach ( $members as $member ) { $values['member'][] = $member; } - $success = LdapAuthenticationPlugin::ldap_modify( $wgAuth->ldapconn, $this->groupDN, $values ); + $success = LdapAuthenticationPlugin::ldap_modify( $ldap->ldapconn, $this->groupDN, $values ); if ( $success ) { $this->fetchGroupInfo(); - $wgAuth->printDebug( "Successfully removed $user->userDN from $this->groupDN", NONSENSITIVE ); + $ldap->printDebug( "Successfully removed $user->userDN from $this->groupDN", NONSENSITIVE ); } else { - $wgAuth->printDebug( "Failed to remove $user->userDN from $this->groupDN", NONSENSITIVE ); + $ldap->printDebug( "Failed to remove $user->userDN from $this->groupDN", NONSENSITIVE ); return false; } } else { return false; } return true; } /** * @param $username * @return bool */ function setMembers( $usernames, $serviceUsernames=array() ) { - global $wgAuth; - + $ldap = LdapAuthenticationPlugin::getInstance(); $members = array(); foreach ( $usernames as $username ) { $userDN = ""; $user = new OpenStackNovaUser( $username ); if ( ! $user->userDN ) { - $wgAuth->printDebug( "Failed to find userDN in setMembers", NONSENSITIVE ); + $ldap->printDebug( "Failed to find userDN in setMembers", NONSENSITIVE ); return false; } $userDN = $user->userDN; $members[] = $userDN; } foreach ( $serviceUsernames as $serviceUsername ) { $userDN = "uid=" . $serviceUsername . "," . $this->usersDN; $members[] = $userDN; } $values = array(); $values['member'] = $members; - $success = LdapAuthenticationPlugin::ldap_modify( $wgAuth->ldapconn, $this->groupDN, $values ); + $success = LdapAuthenticationPlugin::ldap_modify( $ldap->ldapconn, $this->groupDN, $values ); if ( $success ) { $this->fetchGroupInfo(); - $wgAuth->printDebug( "Successfully set members for $this->groupDN", NONSENSITIVE ); + $ldap->printDebug( "Successfully set members for $this->groupDN", NONSENSITIVE ); } else { - $wgAuth->printDebug( "Failed to set members for $this->groupDN", NONSENSITIVE ); + $ldap->printDebug( "Failed to set members for $this->groupDN", NONSENSITIVE ); return false; } return true; } /** * @param $username * @return bool */ function addMember( $username ) { - global $wgAuth; - + $ldap = LdapAuthenticationPlugin::getInstance(); $members = array(); if ( isset( $this->groupInfo[0]['member'] ) ) { $members = $this->groupInfo[0]['member']; array_shift( $members ); } $userDN = ""; $user = new OpenStackNovaUser( $username ); if ( ! $user->userDN ) { - $wgAuth->printDebug( "Failed to find userDN in addMember", NONSENSITIVE ); + $ldap->printDebug( "Failed to find userDN in addMember", NONSENSITIVE ); return false; } $userDN = $user->userDN; $members[] = $userDN; $values = array(); $values['member'] = $members; - $success = LdapAuthenticationPlugin::ldap_modify( $wgAuth->ldapconn, $this->groupDN, $values ); + $success = LdapAuthenticationPlugin::ldap_modify( $ldap->ldapconn, $this->groupDN, $values ); if ( $success ) { $this->fetchGroupInfo(); - $wgAuth->printDebug( "Successfully added $userDN to $this->groupDN", NONSENSITIVE ); + $ldap->printDebug( "Successfully added $userDN to $this->groupDN", NONSENSITIVE ); } else { - $wgAuth->printDebug( "Failed to add $userDN to $this->groupDN", NONSENSITIVE ); + $ldap->printDebug( "Failed to add $userDN to $this->groupDN", NONSENSITIVE ); return false; } return true; } /** * @static * @param $groupName * @param $project OpenStackNovaProject * @return null|OpenStackNovaServiceGroup */ static function getServiceGroupByName( $groupName, $project ) { $group = new OpenStackNovaserviceGroup( $groupName, $project ); if ( $group->groupInfo ) { return $group; } else { return null; } } /** * @static * @param $groupName * @param $project OpenStackNovaProject * @param $initialUser * @return null|OpenStackNovaServiceGroup */ static function createServiceGroup( $inGroupName, $project, $initialUser ) { - global $wgAuth; global $wgOpenStackManagerLDAPUser; global $wgOpenStackManagerLDAPDefaultShell; global $wgOpenStackManagerLDAPServiceGroupBaseDN; global $wgMemc; + $ldap = LdapAuthenticationPlugin::getInstance(); OpenStackNovaLdapConnection::connect(); $projectPrefix = $project->getProjectName() . '.'; # We don't want naming collisions between service groups and actual groups # or users. So, prepend $projectPrefix to the requested group name. if ( strpos( $inGroupName, $projectPrefix, 0 ) === 0 ) { # The user was clever and already added the prefix. $groupName = $inGroupName; $simpleGroupName = substr( $inGroupName, strlen( $projectPrefix ) ); } else { $groupName = $projectPrefix . $inGroupName; $simpleGroupName = $inGroupName; } if ( $initialUser ) { $user = new OpenStackNovaUser( $initialUser ); if ( ! $user->userDN ) { - $wgAuth->printDebug( "Unable to find initial user $initialUser for new group $groupName", NONSENSITIVE ); + $ldap->printDebug( "Unable to find initial user $initialUser for new group $groupName", NONSENSITIVE ); return null; } $initialUserDN = $user->userDN; } $key = wfMemcKey( 'openstackmanager', 'servicegroup', $groupName ); $wgMemc->delete( $key ); $group = array(); $group['objectclass'][] = 'posixgroup'; $group['objectclass'][] = 'groupofnames'; $group['cn'] = $groupName; $groupdn = 'cn=' . $groupName . ',' . $wgOpenStackManagerLDAPServiceGroupBaseDN; - $group['gidnumber'] = OpenStackNovaUser::getNextIdNumber( $wgAuth, 'gidnumber' ); + $group['gidnumber'] = OpenStackNovaUser::getNextIdNumber( $ldap, 'gidnumber' ); $group['member'] = array(); if ( $initialUser ) { $group['member'][] = $initialUserDN; } - $success = LdapAuthenticationPlugin::ldap_add( $wgAuth->ldapconn, $groupdn, $group ); + $success = LdapAuthenticationPlugin::ldap_add( $ldap->ldapconn, $groupdn, $group ); if ( $success ) { - $wgAuth->printDebug( "Successfully added service group $groupdn", NONSENSITIVE ); + $ldap->printDebug( "Successfully added service group $groupdn", NONSENSITIVE ); } else { - $wgAuth->printDebug( "Failed to add service group $groupdn", NONSENSITIVE ); + $ldap->printDebug( "Failed to add service group $groupdn", NONSENSITIVE ); return null; } # stamp out regular expressions! $homeDir = $project->getServiceGroupHomedirPattern(); $homeDir = str_ireplace('%u', $simpleGroupName, $homeDir); $homeDir = str_ireplace('%p', $projectPrefix, $homeDir); # Now create the special SG member $newGroup = self::getServiceGroupByName( $groupName, $project ); $userdn = $newGroup->getSpecialUserDN(); $user = array(); $user['objectclass'][] = 'shadowaccount'; $user['objectclass'][] = 'posixaccount'; $user['objectclass'][] = 'person'; $user['objectclass'][] = 'top'; $user['loginshell'] = $wgOpenStackManagerLDAPDefaultShell; $user['homedirectory'] = $homeDir; $user['uidnumber'] = $group['gidnumber']; $user['gidnumber'] = $group['gidnumber']; $user['uid'] = $groupName; $user['sn'] = $groupName; $user['cn'] = $groupName; - $success = LdapAuthenticationPlugin::ldap_add( $wgAuth->ldapconn, $userdn, $user ); + $success = LdapAuthenticationPlugin::ldap_add( $ldap->ldapconn, $userdn, $user ); if ( $success ) { - $wgAuth->printDebug( "Successfully created service user $userdn", NONSENSITIVE ); + $ldap->printDebug( "Successfully created service user $userdn", NONSENSITIVE ); } else { - $wgAuth->printDebug( "Failed to create service user $userdn", NONSENSITIVE ); + $ldap->printDebug( "Failed to create service user $userdn", NONSENSITIVE ); return null; } # Create Sudo policy so that the service user can chown files in its homedir if ( OpenStackNovaSudoer::createSudoer( $groupName . '-chmod', $project->getProjectName(), array( $groupName ), array(), array( '/bin/chown -R ' . $groupName . '\:' . $groupName . ' ' . $homeDir ), array( '!authenticate' ) ) ) { - $wgAuth->printDebug( "Successfully created chmod sudo policy for $groupName", + $ldap->printDebug( "Successfully created chmod sudo policy for $groupName", NONSENSITIVE ); } else { - $wgAuth->printDebug( "Failed to creat chmod sudo policy for $groupName", + $ldap->printDebug( "Failed to creat chmod sudo policy for $groupName", NONSENSITIVE ); } # Create Sudo policy so that members of the group can sudo as the service user if ( OpenStackNovaSudoer::createSudoer( 'runas-' . $groupName, $project->getProjectName(), array( "%" . $groupName ), array( $groupName ), array( 'ALL' ), array( '!authenticate' ) ) ) { - $wgAuth->printDebug( "Successfully created run-as sudo policy for $groupName", + $ldap->printDebug( "Successfully created run-as sudo policy for $groupName", NONSENSITIVE ); } else { - $wgAuth->printDebug( "Failed to creat run-as sudo policy for $groupName", + $ldap->printDebug( "Failed to creat run-as sudo policy for $groupName", NONSENSITIVE ); } return $newGroup; } /** * @static * @param $groupName * @param $project OpenStackNovaProject * @return bool */ static function deleteServiceGroup( $groupName, $project ) { - global $wgAuth; global $wgMemc; + $ldap = LdapAuthenticationPlugin::getInstance(); $group = self::getServiceGroupByName( $groupName, $project ); if ( !$group ) { - $wgAuth->printDebug( "We are trying to delete a nonexistent service group, $groupName", NONSENSITIVE ); + $ldap->printDebug( "We are trying to delete a nonexistent service group, $groupName", NONSENSITIVE ); return false; } # Delete our special member. - $success = LdapAuthenticationPlugin::ldap_delete( $wgAuth->ldapconn, $group->getSpecialUserDN() ); + $success = LdapAuthenticationPlugin::ldap_delete( $ldap->ldapconn, $group->getSpecialUserDN() ); if ( $success ) { - $wgAuth->printDebug( "Successfully deleted service user $groupName", NONSENSITIVE ); + $ldap->printDebug( "Successfully deleted service user $groupName", NONSENSITIVE ); } else { - $wgAuth->printDebug( "Failed to delete service user $groupName", NONSENSITIVE ); + $ldap->printDebug( "Failed to delete service user $groupName", NONSENSITIVE ); return false; } # Now delete the group. - $success = LdapAuthenticationPlugin::ldap_delete( $wgAuth->ldapconn, $group->groupDN ); + $success = LdapAuthenticationPlugin::ldap_delete( $ldap->ldapconn, $group->groupDN ); if ( $success ) { - $wgAuth->printDebug( "Successfully deleted service group $groupName", NONSENSITIVE ); + $ldap->printDebug( "Successfully deleted service group $groupName", NONSENSITIVE ); $key = wfMemcKey( 'openstackmanager', 'servicegroup', $groupName ); $wgMemc->delete( $key ); } else { - $wgAuth->printDebug( "Failed to delete service group $groupName", NONSENSITIVE ); + $ldap->printDebug( "Failed to delete service group $groupName", NONSENSITIVE ); return false; } return true; } } diff --git a/nova/OpenStackNovaSudoer.php b/nova/OpenStackNovaSudoer.php index a5688c6..4d339c1 100644 --- a/nova/OpenStackNovaSudoer.php +++ b/nova/OpenStackNovaSudoer.php @@ -1,320 +1,318 @@ sudoername = $sudoername; $this->project = $project; OpenStackNovaLdapConnection::connect(); $this->fetchSudoerInfo(); } /** * Fetch the sudoer policy from LDAP and initialize the object * * @return void */ function fetchSudoerInfo() { - global $wgAuth; global $wgMemc; $key = wfMemcKey( 'openstackmanager', 'sudoerinfo', $this->project->getProjectName() . $this->sudoername ); $sudoerInfo = $wgMemc->get( $key ); if ( is_array( $sudoerInfo ) ) { $this->sudoerInfo = $sudoerInfo; } else { - $result = LdapAuthenticationPlugin::ldap_search( $wgAuth->ldapconn, $this->project->getSudoersDN(), + $ldap = LdapAuthenticationPlugin::getInstance(); + $result = LdapAuthenticationPlugin::ldap_search( $ldap->ldapconn, $this->project->getSudoersDN(), '(cn=' . $this->sudoername . ')' ); - $this->sudoerInfo = LdapAuthenticationPlugin::ldap_get_entries( $wgAuth->ldapconn, $result ); + $this->sudoerInfo = LdapAuthenticationPlugin::ldap_get_entries( $ldap->ldapconn, $result ); $wgMemc->set( $key, $this->sudoerInfo, 3600 * 24 ); } if ( $this->sudoerInfo ) { $this->sudoerDN = $this->sudoerInfo[0]['dn']; } } /** * Return the sudo policy name * * @return string */ function getSudoerName() { return $this->sudoername; } /** * Return the policy users * * @return array */ function getSudoerUsers() { if ( isset( $this->sudoerInfo[0]['sudouser'] ) ) { $users = $this->sudoerInfo[0]['sudouser']; array_shift( $users ); return $users; } else { return array(); } } /** * Return the 'run as' users for the policy * * @return array */ function getSudoerRunAsUsers() { if ( isset( $this->sudoerInfo[0]['sudorunasuser'] ) ) { $runasusers = $this->sudoerInfo[0]['sudorunasuser']; array_shift( $runasusers ); return $runasusers; } else { return array(); } } /** * Return the policy commands * * @return array */ function getSudoerCommands() { if ( isset( $this->sudoerInfo[0]['sudocommand'] ) ) { $commands = $this->sudoerInfo[0]['sudocommand']; array_shift( $commands ); return $commands; } else { return array(); } } /** * Return the policy options * * @return array */ function getSudoerOptions() { if ( isset( $this->sudoerInfo[0]['sudooption'] ) ) { $options = $this->sudoerInfo[0]['sudooption']; array_shift( $options ); return $options; } else { return array(); } } /** * Modify a sudoer based on users, commands, and options. * * @param $users * @param $commands * @param $options * @return boolean */ function modifySudoer( $users, $runasuser, $commands, $options ) { - global $wgAuth; global $wgMemc; + $ldap = LdapAuthenticationPlugin::getInstance(); $sudoer = array(); $sudoer['sudouser'] = array(); foreach ( $users as $user ) { $sudoer['sudouser'][] = $user; } $sudoer['sudorunasuser'] = array(); foreach ( $runasuser as $runas ) { $sudoer['sudorunasuser'][] = $runas; } $sudoer['sudocommand'] = array(); foreach ( $commands as $command ) { $sudoer['sudocommand'][] = $command; } $sudoer['sudooption'] = array(); foreach ( $options as $option ) { $sudoer['sudooption'][] = $option; } - $success = LdapAuthenticationPlugin::ldap_modify( $wgAuth->ldapconn, $this->sudoerDN, $sudoer ); + $success = LdapAuthenticationPlugin::ldap_modify( $ldap->ldapconn, $this->sudoerDN, $sudoer ); if ( $success ) { - $wgAuth->printDebug( "Successfully modified sudoer $this->sudoerDN", NONSENSITIVE ); + $ldap->printDebug( "Successfully modified sudoer $this->sudoerDN", NONSENSITIVE ); $key = wfMemcKey( 'openstackmanager', 'sudoerinfo', $this->project->getProjectName() . $this->sudoername ); $wgMemc->delete( $key ); return true; } else { - $wgAuth->printDebug( "Failed to modify sudoer $this->sudoerDN", NONSENSITIVE ); + $ldap->printDebug( "Failed to modify sudoer $this->sudoerDN", NONSENSITIVE ); return false; } } function deleteUser( $username ) { - global $wgAuth; global $wgMemc; if ( isset( $this->sudoerInfo[0]['sudouser'] ) ) { + $ldap = LdapAuthenticationPlugin::getInstance(); $sudousers = $this->sudoerInfo[0]['sudouser']; array_shift( $sudousers ); $index = array_search( $username, $sudousers ); if ( $index === false ) { - $wgAuth->printDebug( "Failed to find userDN in sudouser list", NONSENSITIVE ); + $ldap->printDebug( "Failed to find userDN in sudouser list", NONSENSITIVE ); return false; } unset( $sudousers[$index] ); $values = array(); $values['sudouser'] = array(); foreach ( $sudousers as $sudouser ) { $values['sudouser'][] = $sudouser; } - $success = LdapAuthenticationPlugin::ldap_modify( $wgAuth->ldapconn, $this->sudoerDN, $values ); + $success = LdapAuthenticationPlugin::ldap_modify( $ldap->ldapconn, $this->sudoerDN, $values ); if ( $success ) { $key = wfMemcKey( 'openstackmanager', 'sudoerinfo', $this->project->getProjectName() . $this->sudoername ); $wgMemc->delete( $key ); return true; } } return false; } /** * Get all sudo policies * * @param $projectName * @return array of OpenStackNovaSudoer */ static function getAllSudoersByProject( $projectName ) { - global $wgAuth; - + $ldap = LdapAuthenticationPlugin::getInstance(); OpenStackNovaLdapConnection::connect(); $sudoers = array(); $project = OpenStackNovaProject::getProjectByName( $projectName ); - $result = LdapAuthenticationPlugin::ldap_search( $wgAuth->ldapconn, $project->getSudoersDN(), '(&(cn=*)(objectclass=sudorole))' ); + $result = LdapAuthenticationPlugin::ldap_search( $ldap->ldapconn, $project->getSudoersDN(), '(&(cn=*)(objectclass=sudorole))' ); if ( $result ) { - $entries = LdapAuthenticationPlugin::ldap_get_entries( $wgAuth->ldapconn, $result ); + $entries = LdapAuthenticationPlugin::ldap_get_entries( $ldap->ldapconn, $result ); if ( $entries ) { # First entry is always a count array_shift( $entries ); foreach ( $entries as $entry ) { $sudoer = new OpenStackNovaSudoer( $entry['cn'][0], $project ); $sudoers[] = $sudoer; } } } return $sudoers; } /** * Get a sudoer policy by name. * * @static * @param $sudoerName * @param $projectName * @return null|OpenStackNovaSudoer */ static function getSudoerByName( $sudoerName, $projectName ) { $project = OpenStackNovaProject::getProjectByName( $projectName ); $sudoer = new OpenStackNovaSudoer( $sudoerName, $project ); if ( $sudoer->sudoerInfo ) { return $sudoer; } else { return null; } } /** * Create a new sudoer based on name, users, commands, and options. * Returns null on sudoer creation failure. * * @static * @param $sudoername * @param $projectName * @param $users * @param $commands * @param $options * @return null|OpenStackNovaSudoer */ static function createSudoer( $sudoername, $projectName, $users, $runasuser, $commands, $options ) { - global $wgAuth; - + $ldap = LdapAuthenticationPlugin::getInstance(); OpenStackNovaLdapConnection::connect(); $sudoer = array(); $sudoer['objectclass'][] = 'sudorole'; foreach ( $users as $user ) { $sudoer['sudouser'][] = $user; } foreach ( $runasuser as $runas ) { $sudoer['sudorunasuser'][] = $runas; } foreach ( $commands as $command ) { $sudoer['sudocommand'][] = $command; } foreach ( $options as $option ) { $sudoer['sudooption'][] = $option; } $sudoer['sudohost'][] = 'ALL'; $sudoer['cn'] = $sudoername; $project = OpenStackNovaProject::getProjectByName( $projectName ); $dn = 'cn=' . $sudoername . ',' . $project->getSudoersDN(); - $success = LdapAuthenticationPlugin::ldap_add( $wgAuth->ldapconn, $dn, $sudoer ); + $success = LdapAuthenticationPlugin::ldap_add( $ldap->ldapconn, $dn, $sudoer ); if ( $success ) { - $wgAuth->printDebug( "Successfully added sudoer $sudoername", NONSENSITIVE ); + $ldap->printDebug( "Successfully added sudoer $sudoername", NONSENSITIVE ); return new OpenStackNovaSudoer( $sudoername, $project ); } else { - $wgAuth->printDebug( "Failed to add sudoer $sudoername", NONSENSITIVE ); + $ldap->printDebug( "Failed to add sudoer $sudoername", NONSENSITIVE ); return null; } } /** * Deletes a sudo policy based on the policy name. * * @static * @param $sudoername * @param $projectName * @return bool */ static function deleteSudoer( $sudoername, $projectName ) { - global $wgAuth; global $wgMemc; + $ldap = LdapAuthenticationPlugin::getInstance(); OpenStackNovaLdapConnection::connect(); $project = OpenStackNovaProject::getProjectByName( $projectName ); $sudoer = new OpenStackNovaSudoer( $sudoername, $project ); if ( ! $sudoer ) { - $wgAuth->printDebug( "Sudoer $sudoername does not exist", NONSENSITIVE ); + $ldap->printDebug( "Sudoer $sudoername does not exist", NONSENSITIVE ); return false; } $dn = $sudoer->sudoerDN; - $success = LdapAuthenticationPlugin::ldap_delete( $wgAuth->ldapconn, $dn ); + $success = LdapAuthenticationPlugin::ldap_delete( $ldap->ldapconn, $dn ); if ( $success ) { - $wgAuth->printDebug( "Successfully deleted sudoer $sudoername", NONSENSITIVE ); + $ldap->printDebug( "Successfully deleted sudoer $sudoername", NONSENSITIVE ); $key = wfMemcKey( 'openstackmanager', 'sudoerinfo', $projectName . $sudoername ); $wgMemc->delete( $key ); return true; } else { - $wgAuth->printDebug( "Failed to delete sudoer $sudoername", NONSENSITIVE ); + $ldap->printDebug( "Failed to delete sudoer $sudoername", NONSENSITIVE ); return false; } } } diff --git a/nova/OpenStackNovaUser.php b/nova/OpenStackNovaUser.php index a791e89..1122f18 100644 --- a/nova/OpenStackNovaUser.php +++ b/nova/OpenStackNovaUser.php @@ -1,754 +1,752 @@ username = $username; OpenStackNovaLdapConnection::connect(); $this->fetchUserInfo(); } /** * @return void */ function fetchUserInfo() { - global $wgAuth, $wgUser; + global $wgUser; + $ldap = LdapAuthenticationPlugin::getInstance(); if ( $this->username ) { - $this->userDN = $wgAuth->getUserDN( strtolower( $this->username ) ); - $wgAuth->printDebug( "Fetching userdn using username: $this->userDN ", NONSENSITIVE ); + $this->userDN = $ldap->getUserDN( strtolower( $this->username ) ); + $ldap->printDebug( "Fetching userdn using username: $this->userDN ", NONSENSITIVE ); if ( ! $this->userDN ) { - $this->userDN = $wgAuth->getUserDN( strtolower( $this->username ), false, "uid" ); - $wgAuth->printDebug( "Fetching userdn using shell name: $this->userDN ", NONSENSITIVE ); + $this->userDN = $ldap->getUserDN( strtolower( $this->username ), false, "uid" ); + $ldap->printDebug( "Fetching userdn using shell name: $this->userDN ", NONSENSITIVE ); # We want the actual username, not the id that was passed in. - $this->userInfo = $wgAuth->userInfo; + $this->userInfo = $ldap->userInfo; $this->username = $this->userInfo[0]['cn'][0]; } } else { - $this->userDN = $wgAuth->getUserDN( strtolower( $wgUser->getName() ) ); + $this->userDN = $ldap->getUserDN( strtolower( $wgUser->getName() ) ); $this->username = $wgUser->getName(); - $wgAuth->printDebug( "Fetching userdn using wiki name: " . $wgUser->getName(), NONSENSITIVE ); + $ldap->printDebug( "Fetching userdn using wiki name: " . $wgUser->getName(), NONSENSITIVE ); } - $this->userInfo = $wgAuth->userInfo; + $this->userInfo = $ldap->userInfo; } /** * @return string */ function getUid() { return $this->userInfo[0]['uid'][0]; } /** * @return string */ function getUsername() { return $this->username; } /** * @param string $project * @return array */ function getCredentials( $project='' ) { $userNova = OpenStackNovaController::newFromUser( $this ); if ( $project ) { $token = $userNova->getProjectToken( $project ); } else { $token = $userNova->getUnscopedToken(); } return array( 'token' => $token ); } /** * @param User $user * @return string */ static function loadToken( $user ) { if ( !$user ) { return null; } $user_id = $user->getId(); if ( $user_id != 0 ) { $dbr = wfGetDB( DB_SLAVE ); $row = $dbr->selectRow( 'openstack_tokens', array( 'token' ), array( 'user_id' => $user_id ), __METHOD__ ); if ( $row ) { return $row->token; } } return null; } /** * @param User $user * @param string $token * @return bool */ static function saveToken( $user, $token ) { $user_id = $user->getId(); if ( $user_id != 0 ) { $dbw = wfGetDB( DB_MASTER ); $oldtoken = self::loadToken( $user ); if ( $oldtoken ) { return $dbw->update( 'openstack_tokens', array( 'token' => $token ), array( 'user_id' => $user_id ), __METHOD__ ); } else { return $dbw->insert( 'openstack_tokens', array( 'token' => $token, 'user_id' => $user_id ), __METHOD__ ); } } else { return false; } } /** * @return array */ function getKeypairs() { - global $wgAuth; - $this->fetchUserInfo(); if ( isset( $this->userInfo[0]['sshpublickey'] ) ) { $keys = $this->userInfo[0]['sshpublickey']; $keypairs = array(); array_shift( $keys ); foreach ( $keys as $key ) { $hash = md5( $key ); $keypairs[$hash] = $key; } return $keypairs; } else { - $wgAuth->printDebug( "No keypairs found", NONSENSITIVE ); + $ldap = LdapAuthenticationPlugin::getInstance(); + $ldap->printDebug( "No keypairs found", NONSENSITIVE ); return array(); } } /** * @return bool */ function exists() { $credentials = $this->getCredentials(); return (bool)$credentials['token']; } /** * @return array */ function getProjects() { $controller = OpenStackNovaProject::getController(); $projects = array_keys( $controller->getRoleAssignmentsForUser( $this->getUid() ) ); return $projects; } /** * Returns a list of role this user is a member of. Includes * all projects. * @return array of rolenames */ function getRoles() { - global $wgAuth, $wgMemc; + global $wgMemc; global $wgOpenStackManagerLDAPProjectBaseDN; $key = wfMemcKey( 'openstackmanager', 'roles', $this->username ); $roles = $wgMemc->get( $key ); if ( is_array( $roles ) ) { return $roles; } $controller = OpenStackNovaProject::getController(); $assignments = $controller->getRoleAssignmentsForUser( $this->getUid() ); $everyrole = array(); foreach ($assignments as $projectid => $rolelist ) { $everyrole = array_merge( $everyrole, $rolelist ); } $roleids = array_unique( $everyrole ); $roles = array(); foreach ( $roleids as $roleid ) { $roles[] = OpenStackNovaRole::getRoleNameForId( $roleid ); } $wgMemc->set( $key, $roles, '3600' ); return $roles; } /** * @param $project * @return bool */ function inProject( $project ) { - global $wgAuth; global $wgOpenStackManagerLDAPProjectBaseDN; global $wgMemc; $key = wfMemcKey( 'openstackmanager', "project-$project", $this->userDN ); $cacheLength = 3600; $inProject = $wgMemc->get( $key ); if ( is_int( $inProject ) ) { return (bool)$inProject; } $ret = in_array( $project, $this->getProjects() ); $wgMemc->set( $key, (int)$ret, $cacheLength ); return $ret; } /** * @param $role * @param string $projectname * @return bool */ function inRole( $role, $projectname ) { - global $wgAuth; global $wgMemc; if ( !$projectname ) { return false; } $key = wfMemcKey( 'openstackmanager', "projectrole-$projectname-$role", $this->userDN ); $inRole = $wgMemc->get( $key ); if ( is_int( $inRole ) ) { return (bool)$inRole; } $project = OpenStackNovaProject::getProjectByName( $projectname ); if ( !$project ) { return false; } $role = OpenStackNovaRole::getProjectRoleByName( $role, $project ); if ( ! $role ) { return false; } $ret = false; if ( in_array( $this->getUsername(), $role->getMembers() ) ) { $ret = true; } // Invalidating this properly is hard, so cache just long enough for a single action $wgMemc->set( $key, (int)$ret, 30 ); return $ret; } /** * @param $key * @return bool */ function importKeypair( $key ) { - global $wgAuth; global $wgMemc; + $ldap = LdapAuthenticationPlugin::getInstance(); $keypairs = array(); if ( isset( $this->userInfo[0]['sshpublickey'] ) ) { $keypairs = $this->userInfo[0]['sshpublickey']; array_shift( $keypairs ); } $keypairs[] = $key; $values = array(); $values['sshpublickey'] = $keypairs; - $success = LdapAuthenticationPlugin::ldap_modify( $wgAuth->ldapconn, $this->userDN, $values ); + $success = LdapAuthenticationPlugin::ldap_modify( $ldap->ldapconn, $this->userDN, $values ); if ( $success ) { - $wgAuth->printDebug( "Successfully imported the user's sshpublickey", NONSENSITIVE ); + $ldap->printDebug( "Successfully imported the user's sshpublickey", NONSENSITIVE ); $key = wfMemcKey( 'ldapauthentication', "userinfo", $this->userDN ); - $wgAuth->printDebug( "Deleting memcache key: $key.", NONSENSITIVE ); + $ldap->printDebug( "Deleting memcache key: $key.", NONSENSITIVE ); $wgMemc->delete( $key ); $this->fetchUserInfo(); return true; } else { - $wgAuth->printDebug( "Failed to import the user's sshpublickey", NONSENSITIVE ); + $ldap->printDebug( "Failed to import the user's sshpublickey", NONSENSITIVE ); return false; } } /** * @param $key * @return bool */ function deleteKeypair( $key ) { - global $wgAuth; global $wgMemc; + $ldap = LdapAuthenticationPlugin::getInstance(); if ( isset( $this->userInfo[0]['sshpublickey'] ) ) { $keypairs = $this->userInfo[0]['sshpublickey']; array_shift( $keypairs ); $index = array_search( $key, $keypairs ); if ( $index === false ) { - $wgAuth->printDebug( "Unable to find the sshpublickey to be deleted", NONSENSITIVE ); + $ldap->printDebug( "Unable to find the sshpublickey to be deleted", NONSENSITIVE ); return false; } unset( $keypairs[$index] ); $values = array(); $values['sshpublickey'] = array(); foreach ( $keypairs as $keypair ) { $values['sshpublickey'][] = $keypair; } - $success = LdapAuthenticationPlugin::ldap_modify( $wgAuth->ldapconn, $this->userDN, $values ); + $success = LdapAuthenticationPlugin::ldap_modify( $ldap->ldapconn, $this->userDN, $values ); if ( $success ) { - $wgAuth->printDebug( "Successfully deleted the user's sshpublickey", NONSENSITIVE ); + $ldap->printDebug( "Successfully deleted the user's sshpublickey", NONSENSITIVE ); $key = wfMemcKey( 'ldapauthentication', "userinfo", $this->userDN ); - $wgAuth->printDebug( "Deleting memcache key: $key.", NONSENSITIVE ); + $ldap->printDebug( "Deleting memcache key: $key.", NONSENSITIVE ); $wgMemc->delete( $key ); $this->fetchUserInfo(); return true; } else { - $wgAuth->printDebug( "Failed to delete the user's sshpublickey", NONSENSITIVE ); + $ldap->printDebug( "Failed to delete the user's sshpublickey", NONSENSITIVE ); return false; } } else { - $wgAuth->printDebug( "User does not have a sshpublickey attribute", NONSENSITIVE ); + $ldap->printDebug( "User does not have a sshpublickey attribute", NONSENSITIVE ); return false; } } /** * Does not ensure uniqueness during concurrent use! * Also does not work when resource limits are set for * LDAP queries by the client or the server. * * TODO: write a better and more efficient version of this. * * TODO: Make use of $wgOpenStackManagerIdRanges for all cases. * TODO: Make $wgOpenStackManagerIdRanges use a set of ranges. * * @static * @param $auth * @param $attr * @return mixed|string */ static function getNextIdNumber( $auth, $attr ) { global $wgOpenStackManagerIdRanges; $highest = ''; if ( $attr === 'gidnumber' ) { $filter = "(objectclass=posixgroup)"; $base = GROUPDN; $highest = $wgOpenStackManagerIdRanges['service']['gid']['min']; } else { $filter = "(objectclass=posixaccount)"; $base = USERDN; $highest = '500'; } $basedn = $auth->getBaseDN( $base ); $result = LdapAuthenticationPlugin::ldap_search( $auth->ldapconn, $basedn, $filter ); if ( $result ) { $entries = LdapAuthenticationPlugin::ldap_get_entries( $auth->ldapconn, $result ); if ( $entries ) { if ( $entries['count'] != "0" ) { array_shift( $entries ); $uids = array(); foreach ( $entries as $entry ) { $uids[] = $entry[$attr][0]; } sort( $uids, SORT_NUMERIC ); $highest = array_pop( $uids ) + 1; } } else { $auth->printDebug( "Failed to find any entries when searching for next $attr", NONSENSITIVE ); } } else { $auth->printDebug( "Failed to get a result searching for next $attr", NONSENSITIVE ); } if ( $highest > $wgOpenStackManagerIdRanges['service']['gid']['max']) { $auth->printDebug( "Ran out of service group gids!", NONSENSITIVE ); } $auth->printDebug( "id returned: $highest", NONSENSITIVE ); return $highest; } /** * Hook to add objectclasses and attributes for users being created. * * @static * @param $auth * @param $username * @param $values * @param $writeloc * @param $userdn * @param $result * @return bool */ static function LDAPSetCreationValues( $auth, $username, &$values, $writeloc, &$userdn, &$result ) { global $wgOpenStackManagerLDAPDefaultGid; global $wgOpenStackManagerLDAPDefaultShell; global $wgRequest; $values['objectclass'][] = 'person'; $values['objectclass'][] = 'ldappublickey'; $values['objectclass'][] = 'posixaccount'; $values['objectclass'][] = 'shadowaccount'; $uidnumber = OpenStackNovaUser::getNextIdNumber( $auth, 'uidnumber' ); if ( ! $uidnumber ) { $auth->printDebug( "Unable to allocate a UID", NONSENSITIVE ); $result = false; return false; } $values['cn'] = $username; if ( '' !== $auth->realname ) { $values['displayname'] = $auth->realname; } $shellaccountname = $wgRequest->getText( 'shellaccountname' ); if ( ! preg_match( "/^[a-z][a-z0-9\-_]*$/", $shellaccountname ) ) { $auth->printDebug( "Invalid shell name $shellaccountname", NONSENSITIVE ); $result = false; return false; } $check = ucfirst( $shellaccountname ); if ( ! User::isCreatableName( $check ) ) { $auth->printDebug( "$shellaccountname is not a creatable name.", NONSENSITIVE ); $result = false; return false; } $values['uid'] = $shellaccountname; $base = $auth->getBaseDN( USERDN ); # Though the LDAP plugin checks to see if the user account exists, # it does not check to see if the uid attribute is already used. $result = LdapAuthenticationPlugin::ldap_search( $auth->ldapconn, $base, "(uid=$shellaccountname)" ); if ( $result ) { $entries = LdapAuthenticationPlugin::ldap_get_entries( $auth->ldapconn, $result ); if ( (int)$entries['count'] > 0 ) { $auth->printDebug( "User $shellaccountname already exists.", NONSENSITIVE ); # uid attribute is already in use, fail. $result = false; return false; } } $values['uidnumber'] = $uidnumber; $values['gidnumber'] = $wgOpenStackManagerLDAPDefaultGid; $values['homedirectory'] = '/home/' . $shellaccountname; $values['loginshell'] = $wgOpenStackManagerLDAPDefaultShell; if ( $writeloc === '' ) { $auth->printDebug( "Trying to set the userdn, but write location isn't set.", NONSENSITIVE ); return false; } else { $userdn = 'uid=' . $shellaccountname . ',' . $writeloc; $auth->printDebug( "Using uid as the naming attribute, dn is: $userdn", NONSENSITIVE ); } $auth->printDebug( "User account's objectclasses: ", NONSENSITIVE, $values['objectclass'] ); return true; } /** * Hook to retry setting the creation values. Specifically, this will try to set a new * uid in case there's a race condition. * * @static * @param $auth * @param $username * @param $values * @param $writeloc * @param $userdn * @param $result * @return bool */ static function LDAPRetrySetCreationValues( $auth, $username, &$values, $writeloc, &$userdn, &$result ) { $uidnumber = OpenStackNovaUser::getNextIdNumber( $auth, 'uidnumber' ); if ( ! $uidnumber ) { $result = false; return false; } $values['uidnumber'] = $uidnumber; $result = true; return true; } /** * @static * @param $template * @return bool */ static function LDAPModifyUITemplate( &$template ) { $input = array( 'msg' => 'openstackmanager-shellaccountname', 'type' => 'text', 'name' => 'shellaccountname', 'value' => '', 'helptext' => 'openstackmanager-shellaccountnamehelp' ); $template->set( 'extraInput', array( $input ) ); return true; } static function AbortNewAccount( $user, &$message ) { global $wgRequest; - global $wgAuth; global $wgUser; + $ldap = LdapAuthenticationPlugin::getInstance(); $shellaccountname = $wgRequest->getText( 'shellaccountname' ); if ( ! preg_match( "/^[a-z][a-z0-9\-_]*$/", $shellaccountname ) ) { - $wgAuth->printDebug( "Invalid shell name $shellaccountname", NONSENSITIVE ); + $ldap->printDebug( "Invalid shell name $shellaccountname", NONSENSITIVE ); $message = wfMessage( 'openstackmanager-shellaccountvalidationfail' )->parse(); return false; } - $base = USERDN; - $result = LdapAuthenticationPlugin::ldap_search( $wgAuth->ldapconn, $base, "(uid=$shellaccountname)" ); + $base = USERDN; + $result = LdapAuthenticationPlugin::ldap_search( $ldap->ldapconn, $base, "(uid=$shellaccountname)" ); if ( $result ) { - $entries = LdapAuthenticationPlugin::ldap_get_entries( $wgAuth->ldapconn, $result ); + $entries = LdapAuthenticationPlugin::ldap_get_entries( $ldap->ldapconn, $result ); if ( (int)$entries['count'] > 0 ) { - $wgAuth->printDebug( "User $shellaccountname already exists.", NONSENSITIVE ); + $ldap->printDebug( "User $shellaccountname already exists.", NONSENSITIVE ); $message = wfMessage( 'openstackmanager-shellaccountexists' )->parse(); return false; } } if ( class_exists( 'TitleBlacklist' ) ) { return TitleBlacklistHooks::acceptNewUserName( $shellaccountname, $wgUser, $message, $override = false, $log = true ); } else { return true; } } /** * @static * @param $user * @return bool */ static function LDAPUpdateUser( &$wikiUser ) { if ( $wikiUser->getToken( false ) && isset( $_SESSION['wsOpenStackToken'] ) ) { # If the user has a long-lived token, save the token, # so that it can be refetched. self::saveToken( $wikiUser, $_SESSION['wsOpenStackToken'] ); } return true; } /** * @param $username string * @param $password string * @param $result bool * @return bool */ static function ChainAuth( $username, $password, &$result ) { $user = new OpenStackNovaUser( $username ); $userNova = OpenStackNovaController::newFromUser( $user ); $token = $userNova->authenticate( $username, $password ); if ( $token ) { $result = true; # Add token to session, so that it can be referenced later $_SESSION['wsOpenStackToken'] = $token; } else { $result = false; } return $result; } static function DynamicSidebarGetGroups( &$groups ) { global $wgUser, $wgMemc; if ( $wgUser->isLoggedIn() ) { $key = wfMemcKey( 'openstackmanager', 'roles', $wgUser->getName() ); $roles = $wgMemc->get( $key ); if ( !is_array( $roles ) ) { $user = new OpenStackNovaUser(); $roles = $user->getRoles(); } $groups = array_unique( array_merge( $groups, $roles ) ); } return true; } public static function addUserToBastionProject( $user, &$group ) { global $wgOpenStackManagerBastionProjectId; if( User::groupHasPermission( $group, 'loginviashell' ) ) { // Add the user to the bastion project if not already a // member. $username = $user->getName(); $project = new OpenStackNovaProject( $wgOpenStackManagerBastionProjectId ); if( !in_array( $username, $project->getMembers() ) ) { $project->addMember( $username ); } } return true; } public static function removeUserFromBastionProject( $user, &$group ) { global $wgOpenStackManagerRemoveUserFromBastionProjectOnShellDisable; global $wgOpenStackManagerRemoveUserFromAllProjectsOnShellDisable; global $wgOpenStackManagerBastionProjectId; // Check whether after removing the group the user would still // have the loginviashell permission. foreach ( $user->getEffectiveGroups() as $g ) { // Ignore the group that will be removed. if( $g === $group ) { continue; } // If the user still has the loginviashell permission, we // can immediately return. if( User::groupHasPermission( $g, 'loginviashell' ) ) { return true; } } // At this point we know that the user will not have the // loginviashell permission after the group is removed so we // can remove him from the bastion projects if the // configuration requires that. $username = $user->getName(); if( $wgOpenStackManagerRemoveUserFromAllProjectsOnShellDisable ) { // Get a users projects $userLDAP = new OpenStackNovaUser( $username ); foreach( $userLDAP->getProjects() as $projectId ) { // Remove the user from the project $project = new OpenStackNovaProject( $projectId ); $project->deleteMember( $username ); } } elseif( $wgOpenStackManagerRemoveUserFromBastionProjectOnShellDisable ) { // Remove the user from the bastion project $project = new OpenStackNovaProject( $wgOpenStackManagerBastionProjectId ); if( in_array( $username, $project->getMembers() ) ) { $project->deleteMember( $username ); } } return true; } /** * @param $user User * @param $preferences array * @return bool True */ public static function novaUserPreferences( User $user, array &$preferences ) { $link = Linker::link( SpecialPage::getTitleFor( 'NovaKey' ), wfMessage( 'novakey' )->escaped(), array(), array( 'returnto' => SpecialPage::getTitleFor( 'Preferences' )->getPrefixedText() ) ); $novaUser = new OpenStackNovaUser( $user->getName() ); $preferences['shellusername'] = array( 'type' => 'info', 'label-message' => 'openstackmanager-shellaccountname-pref', 'default' => $novaUser->getUid(), 'section' => 'personal/info', ); $preferences['openstack-sshkeylist'] = array( 'type' => 'info', 'raw' => true, 'default' => self::getKeyList( $novaUser ), 'label-message' => 'openstackmanager-prefs-novapublickey', 'section' => 'openstack/openstack-keys', ); return true; } /** * @param $user OpenStackNovaUser * @return string */ static function getKeyList( $user ) { global $wgOpenStackManagerNovaKeypairStorage; $keyInfo = array(); if ( $wgOpenStackManagerNovaKeypairStorage === 'nova' ) { $projects = $user->getProjects(); $keyInfo['keyname'] = array( 'type' => 'text', 'label-message' => 'openstackmanager-novakeyname', 'default' => '', 'name' => 'keyname', ); $project_keys = array(); foreach ( $projects as $project ) { $project_keys[$project] = $project; } $keyInfo['project'] = array( 'type' => 'select', 'options' => $project_keys, 'label-message' => 'openstackmanager-project', 'name' => 'project', ); } $keyInfo['key'] = array( 'type' => 'textarea', 'default' => '', 'label-message' => 'openstackmanager-novapublickey', 'name' => 'key', ); $out = ''; if ( $wgOpenStackManagerNovaKeypairStorage === 'nova' ) { # TODO: add project filter foreach ( $projects as $project ) { $userCredentials = $user->getCredentials(); $userNova = new OpenStackNovaController( $userCredentials, $project ); $keypairs = $userNova->getKeypairs(); if ( !$keypairs ) { continue; } $out .= Html::element( 'h2', array(), $project ); $headers = array( 'openstackmanager-name', 'openstackmanager-fingerprint' ); $keyRows = array(); foreach ( $keypairs as $keypair ) { $keyRow = array(); SpecialNova::pushResourceColumn( $keyRow, $keypair->getKeyName() ); SpecialNova::pushResourceColumn( $keyRow, $keypair->getKeyFingerprint() ); $keyRows[] = $keyRow; } $out .= SpecialNova::createResourceTable( $headers, $keyRows ); } } elseif ( $wgOpenStackManagerNovaKeypairStorage === 'ldap' ) { $headers = array( 'openstackmanager-keys', 'openstackmanager-actions' ); $keypairs = $user->getKeypairs(); $keyRows = array(); foreach ( $keypairs as $hash => $key ) { $keyRow = array(); SpecialNova::pushResourceColumn( $keyRow, $key, array( 'class' => 'Nova_col' ) ); $actions = array(); $actions[] = SpecialNova::createNovaKeyActionLink( 'openstackmanager-delete', array( 'action' => 'delete', 'hash' => $hash, 'returnto' => SpecialPage::getTitleFor( 'Preferences', false, 'mw-prefsection-openstack' )->getFullText() ) ); SpecialNova::pushRawResourceColumn( $keyRow, SpecialNova::createResourceList( $actions ) ); $keyRows[] = $keyRow; } $out .= SpecialNova::createResourceTable( $headers, $keyRows ); } $out .= Linker::link( SpecialPage::getTitleFor( 'NovaKey' ), wfMessage( 'openstackmanager-addkey' )->escaped(), array(), array( 'returnto' => SpecialPage::getTitleFor( 'Preferences', false, 'mw-prefsection-openstack' )->getFullText() ) ); return $out; } } diff --git a/special/SpecialNovaInstance.php b/special/SpecialNovaInstance.php index b638c05..626b767 100644 --- a/special/SpecialNovaInstance.php +++ b/special/SpecialNovaInstance.php @@ -1,869 +1,868 @@ getUser()->isLoggedIn() ) { $this->notLoggedIn(); return; } $this->userLDAP = new OpenStackNovaUser(); if ( ! $this->userLDAP->exists() ) { $this->noCredentials(); return; } $this->checkTwoFactor(); $project = $this->getRequest()->getVal( 'project' ); $region = $this->getRequest()->getVal( 'region' ); $this->userNova = OpenStackNovaController::newFromUser( $this->userLDAP ); $this->userNova->setProject( $project ); $this->userNova->setRegion( $region ); # ?action= $action = $this->getRequest()->getVal( 'action' ); if ( $action === "create" ) { if ( ! $this->userLDAP->inProject( $project ) ) { $this->notInProject( $project ); return; } $this->createInstance(); } elseif ( $action === "delete" ) { if ( ! $this->userLDAP->inProject( $project ) ) { $this->notInProject( $project ); return; } $this->deleteInstance(); } elseif ( $action === "configure" ) { if ( ! $this->userLDAP->inProject( $project ) ) { $this->notInProject( $project ); return; } $this->configureInstance(); } elseif ( $action === "reboot" ) { if ( ! $this->userLDAP->inProject( $project ) ) { $this->notInProject( $project ); return; } $this->rebootInstance(); } elseif ( $action === "consoleoutput" ) { if ( ! $this->userLDAP->inProject( $project ) ) { $this->notInProject( $project ); return; } $this->getConsoleOutput(); } else { # Fall back to listing all instances $this->listInstances(); } } /** * Handle ?action=create * @return bool */ function createInstance() { global $wgOpenStackManagerPuppetOptions; global $wgOpenStackManagerInstanceBannedInstanceTypes; global $wgOpenStackManagerInstanceDefaultImage; $this->setHeaders(); $this->getOutput()->setPagetitle( $this->msg( 'openstackmanager-createinstance' ) ); $project = $this->getRequest()->getText( 'project' ); $region = $this->getRequest()->getText( 'region' ); if ( ! $this->userLDAP->inRole( 'projectadmin', $project ) ) { $this->notInRole( 'projectadmin', $project ); return false; } $instanceInfo = array(); $instanceInfo['instancename'] = array( 'type' => 'text', 'label-message' => 'openstackmanager-instancename', 'validation-callback' => array( $this, 'validateText' ), 'default' => '', 'section' => 'info', 'name' => 'instancename', ); $instanceTypes = $this->userNova->getInstanceTypes(); $instanceType_keys = array(); foreach ( $instanceTypes as $instanceType ) { $instanceTypeName = $instanceType->getInstanceTypeName(); if ( in_array( $instanceTypeName, $wgOpenStackManagerInstanceBannedInstanceTypes ) ) { continue; } $instanceTypeId = $instanceType->getInstanceTypeId(); $cpus = $instanceType->getNumberOfCPUs(); $ram = $instanceType->getMemorySize(); $root_storage = $instanceType->getRootStorageSize(); $storage = $instanceType->getStorageSize(); // @todo FIXME: Hard coded parentheses. $instanceLabel = $instanceTypeName . ' (' . $this->msg( 'openstackmanager-instancetypelabel', $cpus, $ram, $root_storage, $storage )->text() . ')'; $instanceType_keys[$instanceLabel] = $instanceTypeId; } $instanceInfo['instanceType'] = array( 'type' => 'select', 'label-message' => 'openstackmanager-instancetype', 'section' => 'info', 'options' => $instanceType_keys, 'name' => 'instanceType', ); $instanceInfo['region'] = array( 'type' => 'hidden', 'default' => $region, 'name' => 'region', ); # Image names can't be translated. Get the image, and make an array # where the name points to itself as a value $images = $this->userNova->getImages(); $image_keys = array(); $default = ""; foreach ( $images as $image ) { if ( $image->getImageState() !== "ACTIVE" ) { continue; } $imageName = $image->getImageName(); if ( $imageName === '' ) { continue; } $imageLabel = $imageName; $isDefault = $image->getImageMetadata( 'default' ); if ( $isDefault ) { $default = $imageLabel; } $image_keys[$imageLabel] = $image->getImageId(); } if ( isset( $image_keys[$default] ) ) { $default = $image_keys[$default]; } $instanceInfo['imageType'] = array( 'type' => 'select', 'section' => 'info', 'options' => $image_keys, 'default' => $default, 'label-message' => 'openstackmanager-imagetype', 'name' => 'imageType', ); # Keypair names can't be translated. Get the keys, and make an array # where the name points to itself as a value # TODO: get keypairs as the user, not the admin # $keypairs = $this->userNova->getKeypairs(); # $keypair_keys = array(); # foreach ( array_keys( $keypairs ) as $keypair_key ) { # $keypair_keys[$keypair_key] = $keypair_key; # } # $instanceInfo['keypair'] = array( # 'type' => 'select', # 'section' => 'info', # 'options' => $keypair_keys, # 'label-message' => 'keypair', # ); #$domains = OpenStackNovaDomain::getAllDomains( 'local' ); #$domain_keys = array(); #foreach ( $domains as $domain ) { # $domainname = $domain->getDomainName(); # $domain_keys[$domainname] = $domainname; #} #$instanceInfo['domain'] = array( # 'type' => 'select', # 'section' => 'info', # 'options' => $domain_keys, # 'label-message' => 'openstackmanager-dnsdomain', # 'name' => 'domain', #); $securityGroups = $this->userNova->getSecurityGroups(); $group_keys = array(); $defaults = array(); foreach ( $securityGroups as $securityGroup ) { if ( $securityGroup->getProject() === $project ) { $securityGroupName = $securityGroup->getGroupName(); $group_keys[$securityGroupName] = $securityGroupName; if ( $securityGroupName === "default" ) { $defaults["default"] = "default"; } } } $instanceInfo['groups'] = array( 'type' => 'multiselect', 'section' => 'info', 'options' => $group_keys, 'default' => $defaults, 'label-message' => 'openstackmanager-securitygroups', 'name' => 'groups', ); $instanceInfo['project'] = array( 'type' => 'hidden', 'default' => $project, 'name' => 'project', ); $instanceInfo['action'] = array( 'type' => 'hidden', 'default' => 'create', 'name' => 'action', ); $instanceForm = new HTMLForm( $instanceInfo, $this->getContext(), 'openstackmanager-novainstance' ); $instanceForm->addHeaderText( $this->msg( 'openstackmanager-createinstancepuppetwarning' )->text() . '
', 'puppetinfo' ); $instanceForm->addFooterText( '
', 'puppetinfo' ); $instanceForm->setSubmitID( 'openstackmanager-novainstance-createinstancesubmit' ); $instanceForm->setSubmitCallback( array( $this, 'tryCreateSubmit' ) ); $instanceForm->show(); return true; } /** * Handle ?action=configure * @return bool */ function configureInstance() { global $wgOpenStackManagerPuppetOptions; $this->setHeaders(); $region = $this->getRequest()->getText( 'region' ); $instanceosid = $this->getRequest()->getText( 'instanceid' ); $instance = $this->userNova->getInstance( $instanceosid ); if ( !$instance ) { $this->getOutput()->addWikiMsg( 'openstackmanager-nonexistentresource' ); return false; } $project = $instance->getProject(); if ( !$this->userLDAP->inRole( 'projectadmin', $project ) ) { $this->notInRole( 'projectadmin', $project ); return false; } $instanceid = $instance->getInstanceId(); $instancename = $instance->getInstanceName(); $this->getOutput()->setPagetitle( $this->msg( 'openstackmanager-configureinstance', $instanceid, $instancename ) ); $instanceInfo = array(); $instanceInfo['instanceid'] = array( 'type' => 'hidden', 'default' => $instanceosid, 'name' => 'instanceid', ); $instanceInfo['project'] = array( 'type' => 'hidden', 'default' => $project, 'name' => 'project', ); $instanceInfo['region'] = array( 'type' => 'hidden', 'default' => $region, 'name' => 'region', ); if ( $wgOpenStackManagerPuppetOptions['enabled'] ) { $host = OpenStackNovaHost::getHostByNameAndProject( $instancename, $project, $region ); if ( ! $host ) { $this->getOutput()->addWikiMsg( 'openstackmanager-nonexistenthost' ); return false; } $puppetinfo = $host->getPuppetConfiguration(); $this->setPuppetInfo( $instanceInfo, $puppetinfo ); } $instanceInfo['action'] = array( 'type' => 'hidden', 'default' => 'configure', 'name' => 'action', ); $instanceForm = new HTMLForm( $instanceInfo, $this->getContext(), 'openstackmanager-novainstance' ); $instanceForm->setSubmitID( 'novainstance-form-configureinstancesubmit' ); $instanceForm->setSubmitCallback( array( $this, 'tryConfigureSubmit' ) ); $instanceForm->show(); return true; } /** * Handle ?action=delete * @return bool */ function deleteInstance() { $this->setHeaders(); $project = $this->getRequest()->getText( 'project' ); $region = $this->getRequest()->getText( 'region' ); if ( ! $this->userLDAP->inRole( 'projectadmin', $project ) ) { $this->notInRole( 'projectadmin', $project ); return false; } $instanceosid = $this->getRequest()->getText( 'instanceid' ); if ( ! $this->getRequest()->wasPosted() ) { #TODO: memcache this instanceid lookup $instance = $this->userNova->getInstance( $instanceosid ); if ( !$instance ) { $this->getOutput()->addWikiMsg( 'openstackmanager-nonexistanthost' ); return false; } $this->getOutput()->addWikiMsg( 'openstackmanager-deleteinstancequestion', $instance->getInstanceId() ); $titleid = $instance->getInstanceId(); $titlename = $instance->getInstanceName(); $this->getOutput()->setPagetitle( $this->msg( 'openstackmanager-deleteinstancewithname', $titleid, $titlename ) ); } else { $this->getOutput()->setPagetitle( $this->msg( 'openstackmanager-deleteinstance' ) ); } $instanceInfo = array(); $instanceInfo['instanceid'] = array( 'type' => 'hidden', 'default' => $instanceosid, 'name' => 'instanceid', ); $instanceInfo['project'] = array( 'type' => 'hidden', 'default' => $project, 'name' => 'project', ); $instanceInfo['region'] = array( 'type' => 'hidden', 'default' => $region, 'name' => 'region', ); $instanceInfo['action'] = array( 'type' => 'hidden', 'default' => 'delete', 'name' => 'action', ); $instanceForm = new HTMLForm( $instanceInfo, $this->getContext(), 'openstackmanager-novainstance' ); $instanceForm->setSubmitID( 'novainstance-form-deleteinstancesubmit' ); $instanceForm->setSubmitCallback( array( $this, 'tryDeleteSubmit' ) ); $instanceForm->show(); return true; } /** * Handle ?action=reboot * @return bool */ function rebootInstance() { $this->setHeaders(); $project = $this->getRequest()->getText( 'project' ); $region = $this->getRequest()->getText( 'region' ); if ( ! $this->userLDAP->inRole( 'projectadmin', $project ) ) { $this->notInRole( 'projectadmin', $project ); return false; } $instanceosid = $this->getRequest()->getText( 'instanceid' ); if ( ! $this->getRequest()->wasPosted() ) { # @todo memcache this instanceid lookup $instance = $this->userNova->getInstance( $instanceosid ); if ( !$instance ) { $this->getOutput()->addWikiMsg( 'openstackmanager-nonexistanthost' ); return false; } $this->getOutput()->addWikiMsg( 'openstackmanager-rebootinstancequestion', $instance->getInstanceId() ); $instanceid = $instance->getInstanceId(); $instancename = $instance->getInstanceName(); $this->getOutput()->setPagetitle( $this->msg( 'openstackmanager-rebootinstancewithname', $instanceid, $instancename ) ); } else { $this->getOutput()->setPagetitle( $this->msg( 'openstackmanager-rebootinstance' ) ); } $instanceInfo = array(); $instanceInfo['instanceid'] = array( 'type' => 'hidden', 'default' => $instanceosid, 'name' => 'instanceid', ); $instanceInfo['project'] = array( 'type' => 'hidden', 'default' => $project, 'name' => 'project', ); $instanceInfo['region'] = array( 'type' => 'hidden', 'default' => $region, 'name' => 'region', ); $instanceInfo['action'] = array( 'type' => 'hidden', 'default' => 'reboot', 'name' => 'action', ); $instanceForm = new HTMLForm( $instanceInfo, $this->getContext(), 'openstackmanager-novainstance' ); $instanceForm->setSubmitID( 'novainstance-form-deleteinstancesubmit' ); $instanceForm->setSubmitCallback( array( $this, 'tryRebootSubmit' ) ); $instanceForm->show(); return true; } /** * Handle ?action=console * @return bool */ function getConsoleOutput() { $this->setHeaders(); $instanceosid = $this->getRequest()->getText( 'instanceid' ); $instance = $this->userNova->getInstance( $instanceosid ); $instanceid = $instance->getInstanceId(); $instancename = $instance->getInstanceName(); $this->getOutput()->setPagetitle( $this->msg( 'openstackmanager-consoleoutput', $instanceid, $instancename ) ); $project = $this->getRequest()->getText( 'project' ); if ( ! $this->userLDAP->inRole( 'projectadmin', $project ) ) { $this->notInRole( 'projectadmin', $project ); return; } $consoleOutput = $this->userNova->getConsoleOutput( $instanceosid ); $out = Linker::link( $this->getPageTitle(), $this->msg( 'openstackmanager-backinstancelist' )->escaped() ); $out .= Html::element( 'pre', array(), $consoleOutput ); $this->getOutput()->addHTML( $out ); } /** * Default action * @return void */ function listInstances() { global $wgOpenStackManagerReadOnlyRegions; $this->setHeaders(); $this->getOutput()->addModules( 'ext.openstack.Instance' ); $this->getOutput()->setPagetitle( $this->msg( 'openstackmanager-instancelist' ) ); if ( $this->getUser()->isAllowed( 'listall' ) ) { $projects = OpenStackNovaProject::getAllProjects(); } else { $projects = OpenStackNovaProject::getProjectsByName( $this->userLDAP->getProjects() ); } $this->showProjectFilter( $projects ); $projectfilter = $this->getProjectFilter(); if ( !$projectfilter ) { $this->getOutput()->addWikiMsg( 'openstackmanager-setprojectfilter' ); return null; } $out = ''; foreach ( $projects as $project ) { $projectName = $project->getProjectName(); if ( !in_array( $projectName, $projectfilter ) ) { continue; } $projectactions = array( 'projectadmin' => array() ); $regions = ''; $this->userNova->setProject( $projectName ); foreach ( $this->userNova->getRegions( 'compute' ) as $region ) { if ( in_array( $region, $wgOpenStackManagerReadOnlyRegions ) ) { $regionactions = array( 'projectadmin' => array( $this->msg( 'openstackmanager-creationdisabled' ) ) ); } else { $regionactions = array( 'projectadmin' => array( $this->createActionLink( 'openstackmanager-createinstance', array( 'action' => 'create', 'project' => $projectName, 'region' => $region ) ) ) ); } $instances = $this->getInstances( $projectName, $region ); $regions .= $this->createRegionSection( $region, $projectName, $regionactions, $instances ); } $out .= $this->createProjectSection( $projectName, $projectactions, $regions ); } $this->getOutput()->addHTML( $out ); } function getInstances( $projectName, $region ) { global $wgMemc; $this->userNova->setRegion( $region ); $headers = array( 'openstackmanager-instancename', 'openstackmanager-instanceid', 'openstackmanager-instancestate', 'openstackmanager-instanceip', 'openstackmanager-instancepublicip', 'openstackmanager-securitygroups', 'openstackmanager-imageid', 'openstackmanager-launchtime', 'openstackmanager-actions' ); $instances = $this->userNova->getInstances(); $instanceRows = array(); /** * @var $instance OpenStackNovaInstance */ foreach ( $instances as $instance ) { $instanceRow = array(); $this->pushResourceColumn( $instanceRow, $instance->getInstanceName(), array( 'class' => 'novainstancename' ) ); $host = $instance->getHost(); if ( $host ) { $this->pushRawResourceColumn( $instanceRow, $this->createResourceLink( $host->getFullyQualifiedHostName() ), array( 'class' => 'novainstanceid' ) ); } else { $this->pushResourceColumn( $instanceRow, $instance->getInstanceId(), array( 'class' => 'novainstanceid' ) ); } $state = $instance->getInstanceState(); $taskState = $instance->getInstanceTaskState(); if ( $taskState ) { $stateDisplay = "$state ($taskState)"; } else { $stateDisplay = $state; } $this->pushResourceColumn( $instanceRow, $stateDisplay, array( 'class' => 'novainstancestate' ) ); $this->pushRawResourceColumn( $instanceRow, $this->createResourceList( $instance->getInstancePrivateIPs() ) ); $this->pushRawResourceColumn( $instanceRow, $this->createResourceList( $instance->getInstancePublicIPs() ) ); $this->pushRawResourceColumn( $instanceRow, $this->createResourceList( $instance->getSecurityGroups() ) ); $imageId = $instance->getImageId(); $key = wfMemcKey( 'openstackmanager', "imagename", $imageId ); $imageNameRet = $wgMemc->get( $key ); if ( is_string( $imageNameRet ) ) { $imageName = $imageNameRet; } else { $image = $this->userNova->getImage( $imageId ); if ( $image ) { $imageName = $image->getImageName(); $wgMemc->set( $key, $imageName, 86400 ); } else { $imageName = $this->msg( 'openstackmanager-missingimage' )->text(); } } $this->pushResourceColumn( $instanceRow, $imageName ); $this->pushResourceColumn( $instanceRow, $instance->getLaunchTime() ); $actions = array(); $instanceDataAttributes = array( 'data-osid' => $instance->getInstanceOSId(), 'data-id' => $instance->getInstanceId(), 'data-name' => $instance->getInstanceName(), 'data-project' => $projectName, 'data-region' => $region, 'class' => 'novainstanceaction', ); if ( $this->userLDAP->inRole( 'projectadmin', $projectName ) ) { $actions[] = $this->createActionLink( 'openstackmanager-delete', array( 'action' => 'delete', 'instanceid' => $instance->getInstanceOSId(), 'project' => $projectName, 'region' => $region ), null, $instanceDataAttributes ); $actions[] = $this->createActionLink( 'openstackmanager-reboot', array( 'action' => 'reboot', 'instanceid' => $instance->getInstanceOSId(), 'project' => $projectName, 'region' => $region ), null, $instanceDataAttributes ); $actions[] = $this->createActionLink( 'openstackmanager-configure', array( 'action' => 'configure', 'instanceid' => $instance->getInstanceOSId(), 'project' => $projectName, 'region' => $region ) ); $actions[] = $this->createActionLink( 'openstackmanager-getconsoleoutput', array( 'action' => 'consoleoutput', 'instanceid' => $instance->getInstanceOSId(), 'project' => $projectName, 'region' => $region ), null, $instanceDataAttributes ); } $this->pushRawResourceColumn( $instanceRow, $this->createResourceList( $actions ) ); $instanceRows[] = $instanceRow; } if ( $instanceRows ) { return $this->createResourceTable( $headers, $instanceRows ); } else { return ''; } } /** * @param $formData * @param string $entryPoint * @return bool */ function tryCreateSubmit( $formData, $entryPoint = 'internal' ) { global $wgUser; - global $wgAuth; $domain = OpenStackNovaDomain::getDomainByName( $formData['region'] ); $project = $formData['project']; $region = $formData['region']; if ( !$domain ) { $this->getOutput()->addWikiMsg( 'openstackmanager-invaliddomain' ); return true; } $instance = $this->userNova->createInstance( $formData['instancename'], $formData['imageType'], '', $formData['instanceType'], $formData['groups'] ); if ( $instance ) { // In essex it seems attributes from extensions aren't returned. So, // for now we need to work around this by fetching the instance again. $instanceId = $instance->getInstanceOSId(); $instance = $this->userNova->getInstance( $instanceId ); $image = $this->userNova->getImage( $instance->getImageId() ); $imageName = $image->getImageName(); $this->getOutput()->addWikiMsg( 'openstackmanager-createdinstance', $instance->getInstanceID(), $imageName ); } else { $this->getOutput()->addWikiMsg( 'openstackmanager-createinstancefailed' ); } $out = '
'; $out .= Linker::link( $this->getPageTitle(), $this->msg( 'openstackmanager-backinstancelist' )->escaped() ); $this->getOutput()->addHTML( $out ); return true; } /** * @param $formData * @param string $entryPoint * @return bool */ function tryDeleteSubmit( $formData, $entryPoint = 'internal' ) { global $wgUser; $instanceosid = $formData['instanceid']; $instance = $this->userNova->getInstance( $instanceosid ); if ( ! $instance ) { return false; } $instancename = $instance->getInstanceName(); $instanceid = $instance->getInstanceId(); $result = $instance->deleteInstance( $this->userNova ); if ( $result ) { $this->getOutput()->addWikiMsg( 'openstackmanager-deletedinstance', $instanceid, $instancename ); } else { $this->getOutput()->addWikiMsg( 'openstackmanager-deleteinstancefailed', $instanceid, $instancename ); } $out = '
'; $out .= Linker::link( $this->getPageTitle(), $this->msg( 'openstackmanager-backinstancelist' )->escaped() ); $this->getOutput()->addHTML( $out ); return true; } /** * @param $formData * @param string $entryPoint * @return bool */ function tryRebootSubmit( $formData, $entryPoint = 'internal' ) { $instanceid = $formData['instanceid']; $success = $this->userNova->rebootInstance( $instanceid ); if ( $success ) { OpenStackManagerEvent::storeEventInfo( 'reboot', $this->getUser(), $this->userNova->getInstance( $instanceid ), $formData['project'] ); $this->getOutput()->addWikiMsg( 'openstackmanager-rebootedinstance', $instanceid ); } else { $this->getOutput()->addWikiMsg( 'openstackmanager-rebootinstancefailed', $instanceid ); } $out = '
'; $out .= Linker::link( $this->getPageTitle(), $this->msg( 'openstackmanager-backinstancelist' )->escaped() ); $this->getOutput()->addHTML( $out ); return true; } /** * @param $formData * @param string $entryPoint * @return bool */ function tryConfigureSubmit( $formData, $entryPoint = 'internal' ) { $instance = $this->userNova->getInstance( $formData['instanceid'] ); $host = $instance->getHost(); if ( $host ) { $success = $host->modifyPuppetConfiguration( $this->getPuppetInfo( $formData ) ); if ( $success ) { $instance->editArticle( $this->userNova ); $this->getOutput()->addWikiMsg( 'openstackmanager-modifiedinstance', $instance->getInstanceId(), $instance->getInstanceName() ); } else { $this->getOutput()->addWikiMsg( 'openstackmanager-modifyinstancefailed' ); } } else { $this->getOutput()->addWikiMsg( 'openstackmanager-nonexistanthost' ); } $out = '
'; $out .= Linker::link( $this->getPageTitle(), $this->msg( 'openstackmanager-backinstancelist' )->escaped() ); $this->getOutput()->addHTML( $out ); return true; } #### Puppet related methods ####################################### function getPuppetInfo( $formData ) { global $wgOpenStackManagerPuppetOptions; $puppetinfo = array(); if ( $wgOpenStackManagerPuppetOptions['enabled'] ) { $puppetGroups = OpenStackNovaPuppetGroup::getGroupList( $formData['project'] ); $this->getPuppetInfoByGroup( $puppetinfo, $puppetGroups, $formData ); $puppetGroups = OpenStackNovaPuppetGroup::getGroupList(); $this->getPuppetInfoByGroup( $puppetinfo, $puppetGroups, $formData ); } return $puppetinfo; } function setPuppetInfo( &$instanceInfo, $puppetinfo=array() ) { $project = $instanceInfo['project']['default']; $projectGroups = OpenStackNovaPuppetGroup::getGroupList( $project ); $this->setPuppetInfoByGroups( $instanceInfo, $puppetinfo, $projectGroups ); $globalGroups = OpenStackNovaPuppetGroup::getGroupList(); $this->setPuppetInfoByGroups( $instanceInfo, $puppetinfo, $globalGroups ); } function getPuppetInfoByGroup( &$puppetinfo, $puppetGroups, $formData ) { foreach ( $puppetGroups as $puppetGroup ) { $puppetgroupname = $puppetGroup->getName(); foreach ( $puppetGroup->getClasses() as $class ) { if ( in_array( $class["name"], $formData["$puppetgroupname-puppetclasses"] ) ) { $classname = $class["name"]; if ( !in_array( $classname, $puppetinfo['classes'] ) ) { $puppetinfo['classes'][] = $classname; } } } foreach ( $puppetGroup->getVars() as $variable ) { $variablename = $variable["name"]; if ( isset ( $formData["$puppetgroupname-$variablename"] ) && trim( $formData["$puppetgroupname-$variablename"] ) ) { $puppetinfo['variables'][$variablename] = $formData["$puppetgroupname-$variablename"]; } } } } function setPuppetInfoByGroups( &$instanceInfo, $puppetinfo, $puppetGroups ) { global $wgOpenStackManagerPuppetDocBase; foreach ( $puppetGroups as $puppetGroup ) { $classes = array(); $defaults = array(); $puppetgroupname = $puppetGroup->getName(); $puppetgroupproject = $puppetGroup->getProject(); if ( $puppetgroupproject ) { $section = 'puppetinfo/project'; } else { $section = 'puppetinfo/global'; } foreach ( $puppetGroup->getClasses() as $class ) { $classname = $class["name"]; $classlabel = $classname; if ( $wgOpenStackManagerPuppetDocBase ) { $docentry = str_replace( '::', '/', $classname ); $docurl = $wgOpenStackManagerPuppetDocBase . $docentry . '.html'; # FIXME: This probably doesn't handle modules properly. $doclink = Html::element( 'a', array('href' => $docurl ), $this->msg( 'openstackmanager-puppetdoclink' ) ); $classlabel = "$classname $doclink"; } $classes[$classlabel] = $classname; if ( $puppetinfo && in_array( $classname, $puppetinfo['puppetclass'] ) ) { $defaults[$classname] = $classname; } } $instanceInfo[$puppetgroupname] = array( 'type' => 'info', 'section' => $section, 'label-raw' => Html::element( 'h3', array(), "$puppetgroupname:" ), ); $instanceInfo["${puppetgroupname}-puppetclasses"] = array( 'type' => 'multiselect', 'section' => $section, 'options' => $classes, 'default' => $defaults, 'name' => "${puppetgroupname}-puppetclasses", ); foreach ( $puppetGroup->getVars() as $variable ) { $variablename = $variable["name"]; $default = ''; if ( $puppetinfo && array_key_exists( $variablename, $puppetinfo['puppetvar'] ) ) { $default = $puppetinfo['puppetvar'][$variablename]; } $instanceInfo["${puppetgroupname}-${variablename}"] = array( 'type' => 'text', 'section' => $section, 'label' => $variablename, 'default' => $default, 'name' => "${puppetgroupname}-${variablename}", ); } } } #### End of Puppet related methods ################################ protected function getGroupName() { return 'nova'; } }