/* * Copyright (c) 2014, Oculus VR, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * */ /// \file Rackspace.h /// \brief Helper to class to manage Rackspace servers /// #include "NativeFeatureIncludes.h" #if _RAKNET_SUPPORT_Rackspace==1 && _RAKNET_SUPPORT_TCPInterface==1 #include "Export.h" #include "DS_List.h" #include "RakNetTypes.h" #include "DS_Queue.h" #include "RakString.h" #ifndef __RACKSPACE_H #define __RACKSPACE_H namespace RakNet { class TCPInterface; struct Packet; /// \brief Result codes for Rackspace commands /// /sa Rackspace::EventTypeToString() enum RackspaceEventType { RET_Success_200, RET_Success_201, RET_Success_202, RET_Success_203, RET_Success_204, RET_Cloud_Servers_Fault_500, RET_Service_Unavailable_503, RET_Unauthorized_401, RET_Bad_Request_400, RET_Over_Limit_413, RET_Bad_Media_Type_415, RET_Item_Not_Found_404, RET_Build_In_Progress_409, RET_Resize_Not_Allowed_403, RET_Connection_Closed_Without_Reponse, RET_Unknown_Failure, }; /// \internal enum RackspaceOperationType { RO_CONNECT_AND_AUTHENTICATE, RO_LIST_SERVERS, RO_LIST_SERVERS_WITH_DETAILS, RO_CREATE_SERVER, RO_GET_SERVER_DETAILS, RO_UPDATE_SERVER_NAME_OR_PASSWORD, RO_DELETE_SERVER, RO_LIST_SERVER_ADDRESSES, RO_SHARE_SERVER_ADDRESS, RO_DELETE_SERVER_ADDRESS, RO_REBOOT_SERVER, RO_REBUILD_SERVER, RO_RESIZE_SERVER, RO_CONFIRM_RESIZED_SERVER, RO_REVERT_RESIZED_SERVER, RO_LIST_FLAVORS, RO_GET_FLAVOR_DETAILS, RO_LIST_IMAGES, RO_CREATE_IMAGE, RO_GET_IMAGE_DETAILS, RO_DELETE_IMAGE, RO_LIST_SHARED_IP_GROUPS, RO_LIST_SHARED_IP_GROUPS_WITH_DETAILS, RO_CREATE_SHARED_IP_GROUP, RO_GET_SHARED_IP_GROUP_DETAILS, RO_DELETE_SHARED_IP_GROUP, RO_NONE, }; /// \brief Callback interface to receive the results of operations class RAK_DLL_EXPORT Rackspace2EventCallback { public: Rackspace2EventCallback() {} virtual ~Rackspace2EventCallback() {} virtual void OnAuthenticationResult(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnListServersResult(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnListServersWithDetailsResult(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnCreateServerResult(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnGetServerDetails(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnUpdateServerNameOrPassword(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnDeleteServer(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnListServerAddresses(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnShareServerAddress(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnDeleteServerAddress(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnRebootServer(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnRebuildServer(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnResizeServer(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnConfirmResizedServer(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnRevertResizedServer(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnListFlavorsResult(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnGetFlavorDetailsResult(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnListImagesResult(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnCreateImageResult(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnGetImageDetailsResult(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnDeleteImageResult(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnListSharedIPGroups(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnListSharedIPGroupsWithDetails(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnCreateSharedIPGroup(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnGetSharedIPGroupDetails(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnDeleteSharedIPGroup(RackspaceEventType eventType, const char *htmlAdditionalInfo)=0; virtual void OnConnectionAttemptFailure(RackspaceOperationType operationType, const char *url)=0; }; /// \brief Callback interface to receive the results of operations, with a default result class RAK_DLL_EXPORT RackspaceEventCallback_Default : public Rackspace2EventCallback { public: virtual void ExecuteDefault(const char *callbackName, RackspaceEventType eventType, const char *htmlAdditionalInfo) {(void) callbackName; (void) eventType; (void) htmlAdditionalInfo;} virtual void OnAuthenticationResult(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnAuthenticationResult", eventType, htmlAdditionalInfo);} virtual void OnListServersResult(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnListServersResult", eventType, htmlAdditionalInfo);} virtual void OnListServersWithDetailsResult(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnListServersWithDetailsResult", eventType, htmlAdditionalInfo);} virtual void OnCreateServerResult(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnCreateServerResult", eventType, htmlAdditionalInfo);} virtual void OnGetServerDetails(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnGetServerDetails", eventType, htmlAdditionalInfo);} virtual void OnUpdateServerNameOrPassword(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnUpdateServerNameOrPassword", eventType, htmlAdditionalInfo);} virtual void OnDeleteServer(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnDeleteServer", eventType, htmlAdditionalInfo);} virtual void OnListServerAddresses(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnListServerAddresses", eventType, htmlAdditionalInfo);} virtual void OnShareServerAddress(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnShareServerAddress", eventType, htmlAdditionalInfo);} virtual void OnDeleteServerAddress(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnDeleteServerAddress", eventType, htmlAdditionalInfo);} virtual void OnRebootServer(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnRebootServer", eventType, htmlAdditionalInfo);} virtual void OnRebuildServer(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnRebuildServer", eventType, htmlAdditionalInfo);} virtual void OnResizeServer(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnResizeServer", eventType, htmlAdditionalInfo);} virtual void OnConfirmResizedServer(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnConfirmResizedServer", eventType, htmlAdditionalInfo);} virtual void OnRevertResizedServer(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnRevertResizedServer", eventType, htmlAdditionalInfo);} virtual void OnListFlavorsResult(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnListFlavorsResult", eventType, htmlAdditionalInfo);} virtual void OnGetFlavorDetailsResult(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnGetFlavorDetailsResult", eventType, htmlAdditionalInfo);} virtual void OnListImagesResult(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnListImagesResult", eventType, htmlAdditionalInfo);} virtual void OnCreateImageResult(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnCreateImageResult", eventType, htmlAdditionalInfo);} virtual void OnGetImageDetailsResult(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnGetImageDetailsResult", eventType, htmlAdditionalInfo);} virtual void OnDeleteImageResult(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnDeleteImageResult", eventType, htmlAdditionalInfo);} virtual void OnListSharedIPGroups(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnListSharedIPGroups", eventType, htmlAdditionalInfo);} virtual void OnListSharedIPGroupsWithDetails(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnListSharedIPGroupsWithDetails", eventType, htmlAdditionalInfo);} virtual void OnCreateSharedIPGroup(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnCreateSharedIPGroup", eventType, htmlAdditionalInfo);} virtual void OnGetSharedIPGroupDetails(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnGetSharedIPGroupDetails", eventType, htmlAdditionalInfo);} virtual void OnDeleteSharedIPGroup(RackspaceEventType eventType, const char *htmlAdditionalInfo) {ExecuteDefault("OnDeleteSharedIPGroup", eventType, htmlAdditionalInfo);} virtual void OnConnectionAttemptFailure(RackspaceOperationType operationType, const char *url) {(void) operationType; (void) url;} }; /// \brief Code that uses the TCPInterface class to communicate with the Rackspace API servers /// \pre Compile RakNet with OPEN_SSL_CLIENT_SUPPORT set to 1 /// \pre Packets returned from TCPInterface::OnReceive() must be passed to Rackspace::OnReceive() /// \pre Packets returned from TCPInterface::HasLostConnection() must be passed to Rackspace::OnClosedConnection() class RAK_DLL_EXPORT Rackspace { public: Rackspace(); ~Rackspace(); /// \brief Authenticate with Rackspace servers, required before executing any commands. /// \details All requests to authenticate and operate against Cloud Servers are performed using SSL over HTTP (HTTPS) on TCP port 443. /// Times out after 24 hours - if you get RET_Authenticate_Unauthorized in the RackspaceEventCallback callback, call again /// \sa RackspaceEventCallback::OnAuthenticationResult() /// \param[in] _tcpInterface An instance of TCPInterface, build with OPEN_SSL_CLIENT_SUPPORT 1 and already started /// \param[in] _authenticationURL See http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf . US-based accounts authenticate through auth.api.rackspacecloud.com. UK-based accounts authenticate through lon.auth.api.rackspacecloud.com /// \param[in] _rackspaceCloudUsername Username you registered with Rackspace on their website /// \param[in] _apiAccessKey Obtain your API access key from the Rackspace Cloud Control Panel in the Your Account API Access section. /// \return The address of the authentication server, or UNASSIGNED_SYSTEM_ADDRESS if the connection attempt failed SystemAddress Authenticate(TCPInterface *_tcpInterface, const char *_authenticationURL, const char *_rackspaceCloudUsername, const char *_apiAccessKey); /// \brief Get a list of running servers /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnListServersResult() void ListServers(void); /// \brief Get a list of running servers, with extended details on each server /// \sa GetServerDetails() /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnListServersWithDetailsResult() void ListServersWithDetails(void); /// \brief Create a server /// \details Create a server with a given image (harddrive contents) and flavor (hardware configuration) /// Get the available images with ListImages() /// Get the available flavors with ListFlavors() /// It is possible to configure the server in more detail. See the XML schema at http://docs.rackspacecloud.com/servers/api/v1.0 /// You can execute such a custom command by calling AddOperation() manually. See the implementation of CreateServer for how to do so. /// The server takes a while to build. Call GetServerDetails() to get the current build status. Server id to pass to GetServerDetails() is returned in the field /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnCreateServerResult() /// \param[in] name Name of the server. Only alphanumeric characters, periods, and hyphens are valid. Server Name cannot start or end with a period or hyphen. /// \param[in] imageId Which image (harddrive contents, including OS) to use /// \param[in] flavorId Which flavor (hardware config) to use, primarily how much memory is available. void CreateServer(RakNet::RakString name, RakNet::RakString imageId, RakNet::RakString flavorId); /// \brief Get details on a particular server /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnGetServerDetailsResult() /// \param[in] serverId Which server to get details on. You can call ListServers() to get the list of active servers. void GetServerDetails(RakNet::RakString serverId); /// \brief Changes the name or password for a server /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnUpdateServerNameOrPasswordResult() /// \param[in] serverId Which server to get details on. You can call ListServers() to get the list of active servers. /// \param[in] newName The new server name. Leave blank to leave unchanged. Only alphanumeric characters, periods, and hyphens are valid. Server Name cannot start or end with a period or hyphen. /// \param[in] newPassword The new server password. Leave blank to leave unchanged. void UpdateServerNameOrPassword(RakNet::RakString serverId, RakNet::RakString newName, RakNet::RakString newPassword); /// \brief Deletes a server /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnDeleteServerResult() /// \param[in] serverId Which server to get details on. You can call ListServers() to get the list of active servers. void DeleteServer(RakNet::RakString serverId); /// \brief Lists the IP addresses available to a server /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnListServerAddressesResult() /// \param[in] serverId Which server to operate on. You can call ListServers() to get the list of active servers. void ListServerAddresses(RakNet::RakString serverId); /// \brief Shares an IP address with a server /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnShareServerAddressResult() /// \param[in] serverId Which server to operate on. You can call ListServers() to get the list of active servers. /// \param[in] ipAddress Which IP address. You can call ListServerAddresses() to get the list of addresses for the specified server void ShareServerAddress(RakNet::RakString serverId, RakNet::RakString ipAddress); /// \brief Stops sharing an IP address with a server /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnDeleteServerAddressResult() /// \param[in] serverId Which server to operate on. You can call ListServers() to get the list of active servers. /// \param[in] ipAddress Which IP address. You can call ListServerAddresses() to get the list of addresses for the specified server void DeleteServerAddress(RakNet::RakString serverId, RakNet::RakString ipAddress); /// \brief Reboots a server /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnRebootServerResult() /// \param[in] serverId Which server to operate on. You can call ListServers() to get the list of active servers. /// \param[in] rebootType Should be either "HARD" or "SOFT" void RebootServer(RakNet::RakString serverId, RakNet::RakString rebootType); /// \brief Rebuilds a server with a different image (harddrive contents) /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnRebuildServerResult() /// \param[in] serverId Which server to operate on. You can call ListServers() to get the list of active servers. /// \param[in] imageId Which image (harddrive contents, including OS) to use void RebuildServer(RakNet::RakString serverId, RakNet::RakString imageId); /// \brief Changes the hardware configuration of a server. This does not take effect until you call ConfirmResizedServer() /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnResizeServerResult() /// \sa RevertResizedServer() /// \param[in] serverId Which server to operate on. You can call ListServers() to get the list of active servers. /// \param[in] flavorId Which flavor (hardware config) to use, primarily how much memory is available. void ResizeServer(RakNet::RakString serverId, RakNet::RakString flavorId); /// \brief Confirm a resize for the specified server /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnConfirmResizedServerResult() /// \sa ResizeServer() /// \param[in] serverId Which server to operate on. You can call ListServers() to get the list of active servers. void ConfirmResizedServer(RakNet::RakString serverId); /// \brief Reverts a resize for the specified server /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnRevertResizedServerResult() /// \sa ResizeServer() /// \param[in] serverId Which server to operate on. You can call ListServers() to get the list of active servers. void RevertResizedServer(RakNet::RakString serverId); /// \brief List all flavors (hardware configs, primarily memory) /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnListFlavorsResult() void ListFlavors(void); /// \brief Get extended details about a specific flavor /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnGetFlavorDetailsResult() /// \sa ListFlavors() /// \param[in] flavorId Which flavor (hardware config) void GetFlavorDetails(RakNet::RakString flavorId); /// \brief List all images (software configs, including operating systems), which includes images you create yourself /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnListImagesResult() /// \sa CreateImage() void ListImages(void); /// \brief Images a running server. This essentially copies the harddrive, and lets you start a server with the same harddrive contents later /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnCreateImageResult() /// \sa ListImages() /// \param[in] serverId Which server to operate on. You can call ListServers() to get the list of active servers. /// \param[in] imageName What to call this image void CreateImage(RakNet::RakString serverId, RakNet::RakString imageName); /// \brief Get extended details about a particular image /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnGetImageDetailsResult() /// \sa ListImages() /// \param[in] imageId Which image void GetImageDetails(RakNet::RakString imageId); /// \brief Delete a custom image created with CreateImage() /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnDeleteImageResult() /// \sa ListImages() /// \param[in] imageId Which image void DeleteImage(RakNet::RakString imageId); /// \brief List IP groups /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnListSharedIPGroupsResult() void ListSharedIPGroups(void); /// \brief List IP groups with extended details /// \sa http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20110112.pdf /// \sa RackspaceEventCallback::OnListSharedIPGroupsWithDetailsResult() void ListSharedIPGroupsWithDetails(void); // I don't know what this does void CreateSharedIPGroup(RakNet::RakString name, RakNet::RakString optionalServerId); // I don't know what this does void GetSharedIPGroupDetails(RakNet::RakString groupId); // I don't know what this does void DeleteSharedIPGroup(RakNet::RakString groupId); /// \brief Adds a callback to the list of callbacks to be called when any of the above functions finish executing /// The callbacks are called in the order they are added void AddEventCallback(Rackspace2EventCallback *callback); /// \brief Removes a callback from the list of callbacks to be called when any of the above functions finish executing /// The callbacks are called in the order they are added void RemoveEventCallback(Rackspace2EventCallback *callback); /// \brief Removes all callbacks void ClearEventCallbacks(void); /// Call this anytime TCPInterface returns a packet void OnReceive(Packet *packet); /// Call this when TCPInterface returns something other than UNASSIGNED_SYSTEM_ADDRESS from HasLostConnection() void OnClosedConnection(SystemAddress systemAddress); /// String representation of each RackspaceEventType static const char * EventTypeToString(RackspaceEventType eventType); /// \brief Mostly for internal use, but you can use it to execute an operation with more complex xml if desired /// See the Rackspace.cpp on how to use it void AddOperation(RackspaceOperationType type, RakNet::RakString httpCommand, RakNet::RakString operation, RakNet::RakString xml); protected: DataStructures::List eventCallbacks; struct RackspaceOperation { RackspaceOperationType type; // RakNet::RakString stringInfo; SystemAddress connectionAddress; bool isPendingAuthentication; RakNet::RakString incomingStream; RakNet::RakString httpCommand; RakNet::RakString operation; RakNet::RakString xml; }; TCPInterface *tcpInterface; // RackspaceOperationType currentOperation; // DataStructures::Queue nextOperationQueue; DataStructures::List operations; bool HasOperationOfType(RackspaceOperationType t); unsigned int GetOperationOfTypeIndex(RackspaceOperationType t); RakNet::RakString serverManagementURL; RakNet::RakString serverManagementDomain; RakNet::RakString serverManagementPath; RakNet::RakString storageURL; RakNet::RakString storageDomain; RakNet::RakString storagePath; RakNet::RakString cdnManagementURL; RakNet::RakString cdnManagementDomain; RakNet::RakString cdnManagementPath; RakNet::RakString storageToken; RakNet::RakString authToken; RakNet::RakString rackspaceCloudUsername; RakNet::RakString apiAccessKey; bool ExecuteOperation(RackspaceOperation &ro); void ReadLine(const char *data, const char *stringStart, RakNet::RakString &output); bool ConnectToServerManagementDomain(RackspaceOperation &ro); }; } // namespace RakNet #endif // __RACKSPACE_API_H #endif // _RAKNET_SUPPORT_Rackspace