jae-client 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/.gitignore +12 -0
  2. data/.rspec +2 -0
  3. data/.travis.yml +7 -0
  4. data/.yardopts +9 -0
  5. data/CHANGELOG.md +25 -0
  6. data/Gemfile +3 -0
  7. data/LICENSE +20 -0
  8. data/README.md +122 -0
  9. data/Rakefile +28 -0
  10. data/cloudfoundry.gemspec +35 -0
  11. data/lib/cloudfoundry.rb +35 -0
  12. data/lib/cloudfoundry/client.rb +93 -0
  13. data/lib/cloudfoundry/client/apps.rb +192 -0
  14. data/lib/cloudfoundry/client/info.rb +29 -0
  15. data/lib/cloudfoundry/client/request.rb +89 -0
  16. data/lib/cloudfoundry/client/resources.rb +16 -0
  17. data/lib/cloudfoundry/client/response.rb +68 -0
  18. data/lib/cloudfoundry/client/services.rb +122 -0
  19. data/lib/cloudfoundry/client/users.rb +121 -0
  20. data/lib/cloudfoundry/constants.rb +30 -0
  21. data/lib/cloudfoundry/exception.rb +24 -0
  22. data/lib/cloudfoundry/version.rb +27 -0
  23. data/spec/client/apps_spec.rb +423 -0
  24. data/spec/client/info_spec.rb +92 -0
  25. data/spec/client/resources_spec.rb +53 -0
  26. data/spec/client/services_spec.rb +230 -0
  27. data/spec/client/users_spec.rb +367 -0
  28. data/spec/client_spec.rb +110 -0
  29. data/spec/cloudfoundry_spec.rb +62 -0
  30. data/spec/fixtures/admin_logged/client.yml +85 -0
  31. data/spec/fixtures/admin_logged/users.yml +363 -0
  32. data/spec/fixtures/admin_logged/users_create_action.yml +36 -0
  33. data/spec/fixtures/admin_logged/users_proxy_action.yml +46 -0
  34. data/spec/fixtures/admin_logged/users_proxy_nouser_action.yml +44 -0
  35. data/spec/fixtures/admin_logged/users_unproxy_action.yml +44 -0
  36. data/spec/fixtures/app.js +16 -0
  37. data/spec/fixtures/app.zip +0 -0
  38. data/spec/fixtures/client.yml +151 -0
  39. data/spec/fixtures/client_invalid.yml +85 -0
  40. data/spec/fixtures/cloudfoundry.yml +124 -0
  41. data/spec/fixtures/cloudfoundry_vs_client.yml +159 -0
  42. data/spec/fixtures/no_logged/apps.yml +42 -0
  43. data/spec/fixtures/no_logged/client.yml +42 -0
  44. data/spec/fixtures/no_logged/info.yml +81 -0
  45. data/spec/fixtures/no_logged/resources.yml +42 -0
  46. data/spec/fixtures/no_logged/services.yml +42 -0
  47. data/spec/fixtures/no_logged/users.yml +108 -0
  48. data/spec/fixtures/no_logged/users_login_action.yml +81 -0
  49. data/spec/fixtures/no_logged/users_proxy_action.yml +42 -0
  50. data/spec/fixtures/no_logged/users_unproxy_action.yml +42 -0
  51. data/spec/fixtures/user_logged/apps.yml +828 -0
  52. data/spec/fixtures/user_logged/apps_create_action.yml +42 -0
  53. data/spec/fixtures/user_logged/apps_directory_action.yml +48 -0
  54. data/spec/fixtures/user_logged/apps_download_action.yml +55 -0
  55. data/spec/fixtures/user_logged/apps_file_action.yml +54 -0
  56. data/spec/fixtures/user_logged/apps_start_action.yml +81 -0
  57. data/spec/fixtures/user_logged/apps_stats_action.yml +44 -0
  58. data/spec/fixtures/user_logged/apps_update_info_action.yml +44 -0
  59. data/spec/fixtures/user_logged/apps_upload_filename_action.yml +62 -0
  60. data/spec/fixtures/user_logged/apps_upload_zipfile_action.yml +62 -0
  61. data/spec/fixtures/user_logged/client.yml +85 -0
  62. data/spec/fixtures/user_logged/info.yml +126 -0
  63. data/spec/fixtures/user_logged/resources.yml +44 -0
  64. data/spec/fixtures/user_logged/resources_check_action.yml +42 -0
  65. data/spec/fixtures/user_logged/services.yml +354 -0
  66. data/spec/fixtures/user_logged/services_bind_action.yml +161 -0
  67. data/spec/fixtures/user_logged/services_create_action.yml +83 -0
  68. data/spec/fixtures/user_logged/services_unbind_action.yml +122 -0
  69. data/spec/fixtures/user_logged/services_unbind_fail_action.yml +122 -0
  70. data/spec/fixtures/user_logged/users.yml +299 -0
  71. data/spec/fixtures/user_logged/users_proxy_action.yml +44 -0
  72. data/spec/fixtures/user_logged/users_unproxy_action.yml +44 -0
  73. data/spec/spec_helper.rb +29 -0
  74. data/spec/support/cf_connection_helper.rb +26 -0
  75. data/spec/support/vcr.rb +8 -0
  76. metadata +301 -0
@@ -0,0 +1,29 @@
1
+ module CloudFoundry
2
+ class Client
3
+ # CloudFoundry API Info methods.
4
+ module Info
5
+ # Returns information about the target cloud and, if logged, information about the user account.
6
+ #
7
+ # @return [Hash] Information about the target cloud and, if logged, information about the user account.
8
+ def cloud_info()
9
+ get(CloudFoundry::Client::CLOUD_INFO_PATH)
10
+ end
11
+
12
+ # Returns information about system runtimes that are available on the target cloud.
13
+ #
14
+ # @return [Hash] System Runtimes available on the target cloud.
15
+ def cloud_runtimes_info()
16
+ get(CloudFoundry::Client::CLOUD_RUNTIMES_INFO_PATH)
17
+ end
18
+
19
+ # Returns information about system services that are available on the target cloud.
20
+ #
21
+ # @return [Hash] System Services available on the target cloud.
22
+ # @authenticated True
23
+ def cloud_services_info()
24
+ require_login
25
+ get(CloudFoundry::Client::CLOUD_SERVICES_INFO_PATH)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,89 @@
1
+ module CloudFoundry
2
+ class Client
3
+ # CloudFoundry API Request Methods.
4
+ module Request
5
+
6
+ # Performs an HTTP GET request to the target cloud.
7
+ #
8
+ # @param [String] path Path to request at target cloud.
9
+ # @param [Hash] options
10
+ # @option options [Boolean] :raw true if response must not be parsed.
11
+ def get(path, options = {})
12
+ request(:get, path, options)
13
+ end
14
+
15
+ # Performs an HTTP POST request to the target cloud.
16
+ #
17
+ # @param [String] path Path to request at target cloud.
18
+ # @param [Hash] body Body of the request to the target cloud.
19
+ # @param [Hash] options
20
+ # @option options [Boolean] :raw true if response must not be parsed.
21
+ def post(path, body = {}, options = {})
22
+ request(:post, path, options, body)
23
+ end
24
+
25
+ # Performs an HTTP PUT request to the target cloud.
26
+ #
27
+ # @param [String] path Path to request at target cloud.
28
+ # @param [Hash] body Body of the request to the target cloud.
29
+ # @param [Hash] options
30
+ # @option options [Boolean] :raw true if response must not be parsed.
31
+ def put(path, body = {}, options = {})
32
+ request(:put, path, options, body)
33
+ end
34
+
35
+ # Performs an HTTP DELETE request to the target cloud.
36
+ #
37
+ # @param [String] path Path to request at target cloud.
38
+ # @param [Hash] options
39
+ # @option options [Boolean] :raw true if response must not be parsed.
40
+ def delete(path, options = {})
41
+ request(:delete, path, options)
42
+ end
43
+
44
+ private
45
+
46
+ # Sets a new connection to target cloud.
47
+ #
48
+ # @param [Hash] options
49
+ # @option options [Boolean] :raw true if response must not be parsed.
50
+ # @return [Faraday::Connection] A Faraday Connection.
51
+ def connection(options = {})
52
+ connection_options = {
53
+ :proxy => @proxy_url,
54
+ :url => @target_url
55
+ }
56
+ connection = Faraday.new(connection_options) do |builder|
57
+ builder.use Faraday::Request::Multipart
58
+ builder.use Faraday::Request::UrlEncoded
59
+ builder.use FaradayMiddleware::EncodeJson unless options[:raw]
60
+ builder.adapter @net_adapter
61
+ builder.use CloudFoundry::Client::Response::ParseJSON unless options[:raw]
62
+ builder.use CloudFoundry::Client::Response::CloudError
63
+ end
64
+ end
65
+
66
+ # Performs a request to the target cloud.
67
+ #
68
+ # @param [Symbol] method HTTP method to use.
69
+ # @param [String] path Path to request at target cloud.
70
+ # @param [Hash] options
71
+ # @param [Hash] payload Body of the request to the target cloud.
72
+ # @option options [Boolean] :raw true if response must not be parsed.
73
+ def request(method, path, options = {}, payload = nil)
74
+ headers = {}
75
+ headers["User-Agent"] = "cloudfoundry-client-" + CloudFoundry::Client::VERSION
76
+ headers["AUTHORIZATION"] = @auth_token if @auth_token
77
+ headers["PROXY-USER"] = @proxy_user if @proxy_user
78
+ headers["X-VCAP-Trace"] = @trace_key if @trace_key
79
+ headers["Accept"] = "application/json" unless options[:raw]
80
+ headers["Content-Type"] = "application/json" unless options[:raw]
81
+ response = connection(options).send(method, path) do |request|
82
+ request.headers = headers
83
+ request.body = payload unless payload && payload.empty?
84
+ end
85
+ options[:raw] ? response : response.body
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,16 @@
1
+ module CloudFoundry
2
+ class Client
3
+ # CloudFoundry API Resources methods.
4
+ module Resources
5
+ # Checks which resources are needed to send to the target cloud when uploading application bits.
6
+ #
7
+ # @param [Array] resources A resources manifest.
8
+ # @return [Array] A resources manifest.
9
+ # @authenticated True
10
+ def check_resources(resources)
11
+ require_login
12
+ post(CloudFoundry::Client::RESOURCES_PATH, resources)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,68 @@
1
+ module CloudFoundry
2
+ class Client
3
+ # CloudFoundry Faraday Response Middleware.
4
+ module Response
5
+ # Faraday Response Middleware to parse cloud JSON responses.
6
+ class ParseJSON < Faraday::Response::Middleware
7
+ # Parses a JSON response.
8
+ #
9
+ # @param [String] body HTTP body response.
10
+ # @return [Hash] Parsed body response with symbolized names (keys).
11
+ # @raise [CloudFoundry::Client::Exception::BadResponse] when body can not be parsed.
12
+ def parse(body)
13
+ case body
14
+ when " " then nil
15
+ else JSON.parse(body, :symbolize_names => true, :symbolize_keys => true)
16
+ end
17
+ rescue JSON::ParserError
18
+ raise CloudFoundry::Client::Exception::BadResponse, "Can't parse response into JSON:" + body
19
+ end
20
+ end
21
+
22
+ # Faraday Response Middleware to parse cloud errors.
23
+ class CloudError < Faraday::Response::Middleware
24
+ # Checks if an error is returned by target cloud.
25
+ #
26
+ # @param [Hash] env Faraday environment.
27
+ # @raise [CloudFoundry::Client::Exception::BadRequest] when HTTP status is 400.
28
+ # @raise [CloudFoundry::Client::Exception::Forbidden] when HTTP status is 403.
29
+ # @raise [CloudFoundry::Client::Exception::NotFound] when HTTP status is 404.
30
+ # @raise [CloudFoundry::Client::Exception::ServerError] when HTTP status is 500.
31
+ # @raise [CloudFoundry::Client::Exception::BadGateway] when HTTP status is 502.
32
+ def on_complete(env)
33
+ if env[:status].to_i >= 400
34
+ err = case env[:status].to_i
35
+ when 400 then CloudFoundry::Client::Exception::BadRequest
36
+ when 403 then CloudFoundry::Client::Exception::Forbidden
37
+ when 404 then CloudFoundry::Client::Exception::NotFound
38
+ when 500 then CloudFoundry::Client::Exception::ServerError
39
+ when 502 then CloudFoundry::Client::Exception::BadGateway
40
+ end
41
+ raise err, parse_cloud_error_message(env[:status], env[:body])
42
+ end
43
+ end
44
+
45
+ # Parses a CloudFoundry error message.
46
+ #
47
+ # @param [String] status Faraday HTTP response status.
48
+ # @param [String] body Faraday HTTP response body.
49
+ # @return [String] CloudFoundry error message.
50
+ def parse_cloud_error_message(status, body)
51
+ parsed_body = JSON.parse(body, :symbolize_names => true)
52
+ if parsed_body && parsed_body[:code] && parsed_body[:description]
53
+ description = parsed_body[:description].gsub("\"","'")
54
+ "Error #{parsed_body[:code]}: #{description}"
55
+ else
56
+ "Error (HTTP #{status}): #{body}"
57
+ end
58
+ rescue JSON::ParserError
59
+ if body.nil? || body.empty?
60
+ "Error (#{status}): No Response Received"
61
+ else
62
+ "Error (JSON #{status}): #{body}"
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,122 @@
1
+ module CloudFoundry
2
+ class Client
3
+ # CloudFoundry API Provisioned Services methods.
4
+ module Services
5
+ # Returns a list of provisioned services that are available on the target cloud.
6
+ #
7
+ # @return [Hash] List of provisioned services available on the target cloud.
8
+ # @authenticated True
9
+ def list_services
10
+ require_login
11
+ get(CloudFoundry::Client::SERVICES_PATH)
12
+ end
13
+
14
+ # Returns information about a provisioned service on the target cloud.
15
+ #
16
+ # @param [String] name The provisioned service name.
17
+ # @return [Hash] Provisioned service information on the target cloud.
18
+ # @raise [CloudFoundry::Client::Exception::BadParams] when provisioned service name is blank.
19
+ # @authenticated True
20
+ def service_info(name)
21
+ require_login
22
+ raise CloudFoundry::Client::Exception::BadParams, "Name cannot be blank" if name.nil? || name.empty?
23
+ get("#{CloudFoundry::Client::SERVICES_PATH}/#{name}")
24
+ end
25
+
26
+ # Creates a new provisioned service on the target cloud.
27
+ #
28
+ # @param [String] service The system service to provision.
29
+ # @param [String] name The provisioned service name.
30
+ # @return [Boolean] Returns true if provisioned service is created.
31
+ # @raise [CloudFoundry::Client::Exception::BadParams] when system service is blank.
32
+ # @raise [CloudFoundry::Client::Exception::BadParams] when system service is not a valid service at target cloud.
33
+ # @raise [CloudFoundry::Client::Exception::BadParams] when provisioned service name is blank.
34
+ # @authenticated True
35
+ def create_service(service, name)
36
+ require_login
37
+ raise CloudFoundry::Client::Exception::BadParams, "Service cannot be blank" if service.nil? || service.empty?
38
+ raise CloudFoundry::Client::Exception::BadParams, "Name cannot be blank" if name.nil? || name.empty?
39
+ service_hash = nil
40
+ services = cloud_services_info() || []
41
+ services.each do |service_type, service_value|
42
+ service_value.each do |vendor, vendor_value|
43
+ vendor_value.each do |version, service_info|
44
+ if service == service_info[:vendor]
45
+ service_hash = {
46
+ :type => service_info[:type],
47
+ :vendor => vendor,
48
+ :version => version,
49
+ :tier => "free"
50
+ }
51
+ break
52
+ end
53
+ end
54
+ end
55
+ end
56
+ raise CloudFoundry::Client::Exception::BadParams, "Service [#{service}] is not a valid service" unless service_hash
57
+ service_hash[:name] = name
58
+ post(CloudFoundry::Client::SERVICES_PATH, service_hash)
59
+ true
60
+ end
61
+
62
+ # Deletes a provisioned service on the target cloud.
63
+ #
64
+ # @param [String] name The provisioned service name.
65
+ # @return [Boolean] Returns true if provisioned service is deleted.
66
+ # @raise [CloudFoundry::Client::Exception::BadParams] when provisioned service name is blank.
67
+ # @authenticated True
68
+ def delete_service(name)
69
+ require_login
70
+ raise CloudFoundry::Client::Exception::BadParams, "Name cannot be blank" if name.nil? || name.empty?
71
+ delete("#{CloudFoundry::Client::SERVICES_PATH}/#{name}", :raw => true)
72
+ true
73
+ end
74
+
75
+ # Binds a provisioned service to an application on the target cloud.
76
+ #
77
+ # @param [String] name The provisioned service name.
78
+ # @param [String] appname The application name.
79
+ # @return [Boolean] Returns true if provisioned service is binded to application.
80
+ # @raise [CloudFoundry::Client::Exception::BadParams] when provisioned service name is blank.
81
+ # @raise [CloudFoundry::Client::Exception::BadParams] when provisioned service is already binded to application.
82
+ # @raise [CloudFoundry::Client::Exception::BadParams] when application name is blank.
83
+ # @authenticated True
84
+ def bind_service(name, appname)
85
+ require_login
86
+ raise CloudFoundry::Client::Exception::BadParams, "Service Name cannot be blank" if name.nil? || name.empty?
87
+ raise CloudFoundry::Client::Exception::BadParams, "Application Name cannot be blank" if appname.nil? || appname.empty?
88
+ service = service_info(name)
89
+ app = app_info(appname)
90
+ services = app[:services] || []
91
+ service_exists = services.index(name)
92
+ raise CloudFoundry::Client::Exception::BadParams, "Service [#{name}] is already binded to [#{appname}]" if service_exists
93
+ app[:services] = services << name
94
+ update_app(appname, app)
95
+ true
96
+ end
97
+
98
+ # Unbinds a provisioned service from an application on the target cloud.
99
+ #
100
+ # @param [String] name The provisioned service name.
101
+ # @param [String] appname The application name.
102
+ # @return [Boolean] Returns true if provisioned service is unbinded from application.
103
+ # @raise [CloudFoundry::Client::Exception::BadParams] when provisioned service name is blank.
104
+ # @raise [CloudFoundry::Client::Exception::BadParams] when provisioned service is not binded to application.
105
+ # @raise [CloudFoundry::Client::Exception::BadParams] when application name is blank.
106
+ # @authenticated True
107
+ def unbind_service(name, appname)
108
+ require_login
109
+ raise CloudFoundry::Client::Exception::BadParams, "Service Name cannot be blank" if name.nil? || name.empty?
110
+ raise CloudFoundry::Client::Exception::BadParams, "Application Name cannot be blank" if appname.nil? || appname.empty?
111
+ service = service_info(name)
112
+ app = app_info(appname)
113
+ services = app[:services] || []
114
+ service_deleted = services.delete(name)
115
+ raise CloudFoundry::Client::Exception::BadParams, "Service [#{name}] is not binded to [#{name}]" unless service_deleted
116
+ app[:services] = services
117
+ update_app(appname, app)
118
+ true
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,121 @@
1
+ module CloudFoundry
2
+ class Client
3
+ # CloudFoundry API Users methods.
4
+ module Users
5
+ # Logs the user in and returns the auth_token provided by the target cloud.
6
+ #
7
+ # @param [String] email The user's email.
8
+ # @param [String] password The user's password.
9
+ # @return [String] CloudFoundry API Authorization Token.
10
+ # @raise [CloudFoundry::Client::Exception::BadParams] when email is blank.
11
+ # @raise [CloudFoundry::Client::Exception::BadParams] when password is blank.
12
+ # @raise [CloudFoundry::Client::Exception::Forbidden] when login fails.
13
+ def login(email, password)
14
+ raise CloudFoundry::Client::Exception::BadParams, "Email cannot be blank" if email.nil? || email.empty?
15
+ raise CloudFoundry::Client::Exception::BadParams, "Password cannot be blank" if password.nil? || password.empty?
16
+ response_info = post("#{CloudFoundry::Client::USERS_PATH}/#{email}/tokens", {:password => password})
17
+ raise CloudFoundry::Client::Exception::Forbidden, "Login failed" unless response_info && response_info[:token]
18
+ @user = email
19
+ @proxy_user = nil
20
+ @auth_token = response_info[:token]
21
+ end
22
+
23
+ # Checks if the user is logged in at the cloud target.
24
+ #
25
+ # @return [Boolean] Returns true if user is logged in, false otherwise.
26
+ def logged_in?
27
+ return false unless cloud_info = cloud_info()
28
+ return false unless cloud_info[:user]
29
+ return false unless cloud_info[:usage]
30
+ @user = cloud_info[:user]
31
+ true
32
+ end
33
+
34
+ # Sets a user proxied access
35
+ #
36
+ # @param [String] email The user's email to be proxied.
37
+ # @return [String] Proxied user.
38
+ # @raise [CloudFoundry::Client::Exception::BadParams] when email is blank.
39
+ # @admin True
40
+ def set_proxy_user(email)
41
+ raise CloudFoundry::Client::Exception::BadParams, "Email cannot be blank" if email.nil? || email.empty?
42
+ @proxy_user = email
43
+ end
44
+
45
+ # Unsets a user proxied access
46
+ #
47
+ # @return [nil]
48
+ def unset_proxy_user()
49
+ @proxy_user = nil
50
+ end
51
+
52
+ # Returns the list of users on the target cloud.
53
+ #
54
+ # @return [Hash] List of users on the target cloud.
55
+ # @admin True
56
+ def list_users()
57
+ require_login
58
+ get(CloudFoundry::Client::USERS_PATH)
59
+ end
60
+
61
+ # Returns information about a user on the target cloud.
62
+ #
63
+ # @param [String] email The user's email.
64
+ # @return [Hash] User information on the target cloud.
65
+ # @raise [CloudFoundry::Client::Exception::BadParams] when email is blank.
66
+ # @authenticated True
67
+ # @admin Only when retrieving information about others users.
68
+ def user_info(email)
69
+ require_login
70
+ raise CloudFoundry::Client::Exception::BadParams, "Email cannot be blank" if email.nil? || email.empty?
71
+ get("#{CloudFoundry::Client::USERS_PATH}/#{email}")
72
+ end
73
+
74
+ # Creates a new user on the target cloud.
75
+ #
76
+ # @param [String] email The user's email.
77
+ # @param [String] password The user's password.
78
+ # @return [Boolean] Returns true if user is created.
79
+ # @raise [CloudFoundry::Client::Exception::BadParams] when email is blank.
80
+ # @raise [CloudFoundry::Client::Exception::BadParams] when password is blank.
81
+ def create_user(email, password)
82
+ raise CloudFoundry::Client::Exception::BadParams, "Email cannot be blank" if email.nil? || email.empty?
83
+ raise CloudFoundry::Client::Exception::BadParams, "Password cannot be blank" if password.nil? || password.empty?
84
+ post(CloudFoundry::Client::USERS_PATH, {:email => email, :password => password})
85
+ true
86
+ end
87
+
88
+ # Updates the user's password on the target cloud.
89
+ #
90
+ # @param [String] email The user's email.
91
+ # @param [String] password The user's password.
92
+ # @return [Boolean] Returns true if user is updated.
93
+ # @raise [CloudFoundry::Client::Exception::BadParams] when email is blank.
94
+ # @raise [CloudFoundry::Client::Exception::BadParams] when password is blank.
95
+ # @authenticated True
96
+ # @admin Only when updating password for others users.
97
+ def update_user(email, password)
98
+ require_login
99
+ raise CloudFoundry::Client::Exception::BadParams, "Email cannot be blank" if email.nil? || email.empty?
100
+ raise CloudFoundry::Client::Exception::BadParams, "Password cannot be blank" if password.nil? || password.empty?
101
+ user_info = user_info(email)
102
+ user_info[:password] = password
103
+ put("#{CloudFoundry::Client::USERS_PATH}/#{email}", user_info)
104
+ true
105
+ end
106
+
107
+ # Deletes a user on the target cloud.
108
+ #
109
+ # @param [String] email The user's email.
110
+ # @return [Boolean] Returns true if user is deleted.
111
+ # @raise [CloudFoundry::Client::Exception::BadParams] when email is blank.
112
+ # @admin True
113
+ def delete_user(email)
114
+ require_login
115
+ raise CloudFoundry::Client::Exception::BadParams, "Email cannot be blank" if email.nil? || email.empty?
116
+ delete("#{CloudFoundry::Client::USERS_PATH}/#{email}", :raw => true)
117
+ true
118
+ end
119
+ end
120
+ end
121
+ end