sfrest 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7045fc0312fa3b50c38c0605a27b900a9a50a08e
4
+ data.tar.gz: 8f31a1b7ecc1e6d1bb13a47e36d7fc20c05bbdc4
5
+ SHA512:
6
+ metadata.gz: c1273edd11d4687be24897f2d76e7210abde28982f8377fcc54acf909af4f7890abedbc9aba15cb4b5c4f9453886243d5bdee90ac0a404d5ed3089ba1e16ae50
7
+ data.tar.gz: 5021fe6693f4af1bd6624cf9956c9568b5373e24a5bbe61ee483bdde5c08c8ec982f9dcfee990d934ea6699407516bc56fe3d79026c99299ac98cdb414dec06a
@@ -0,0 +1,16 @@
1
+ module SFRest
2
+ # Get all the audit devents.
3
+ class Audit
4
+ # @param [SFRest::Connection] conn
5
+ def initialize(conn)
6
+ @conn = conn
7
+ end
8
+
9
+ # Lists audit events.
10
+ # @return [Hash{'count' => Integer, 'changes' => [Hash, Hash]}]
11
+ def list_audit_events
12
+ current_path = '/api/v1/audit'
13
+ @conn.get(current_path)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,46 @@
1
+ module SFRest
2
+ # Backup a site or restore onto that site
3
+ class Backup
4
+ # @param [SFRest::Connection] conn
5
+ def initialize(conn)
6
+ @conn = conn
7
+ end
8
+
9
+ # cool stuff goes here
10
+ # @param [Integer] site_id the node id of the site node
11
+ # @return [Hash]
12
+ def get_backups(site_id, datum = nil)
13
+ current_path = "/api/v1/sites/#{site_id}/backups"
14
+ pb = SFRest::Pathbuilder.new
15
+ @conn.get URI.parse(URI.encode(pb.build_url_query(current_path, datum))).to_s
16
+ end
17
+
18
+ # Deletes a site backup.
19
+ # @param [Integer] site_id Node id of site
20
+ # @param [Integer] backup_id Id of backup to delete
21
+ def delete_backup(site_id, backup_id)
22
+ current_path = "/api/v1/sites/#{site_id}/backups/#{backup_id}"
23
+ @conn.delete(current_path)
24
+ end
25
+
26
+ # Backs up a site.
27
+ # @param [Integer] site_id
28
+ # @param [Hash] datum Options to the backup
29
+ # @option datum [String] 'label'
30
+ # @option datum [Url] 'callback_url'
31
+ # @option datum [String] 'callback_method' GET|POST
32
+ # @option datum [Json] 'caller_data' json encoded string
33
+ def create_backup(site_id, datum = nil)
34
+ current_path = "/api/v1/sites/#{site_id}/backup"
35
+ @conn.post(current_path, datum.to_json)
36
+ end
37
+
38
+ # Gets a url to download a backup
39
+ # @param [Integer] site_id Node id of site
40
+ # @param [Integer] backup_id Id of backup to delete
41
+ # @param [Integer] lifetime TTL of the url
42
+ def backup_url(site_id, backup_id, lifetime = 60)
43
+ @conn.get("/api/v1/sites/#{site_id}/backups/#{backup_id}/url?lifetime=#{lifetime}")
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,173 @@
1
+ module SFRest
2
+ # Generic http methods
3
+ # accessors for all the sub classes.
4
+ class Connection
5
+ attr_accessor :base_url, :username, :password
6
+
7
+ # @param [String] url base url of the SF endpoint e.g. https://www.sfdev.acsitefactory.com
8
+ # @param [String] user api user
9
+ # @param [String] password api password
10
+ def initialize(url, user, password)
11
+ @base_url = url
12
+ @username = user
13
+ @password = password
14
+ end
15
+
16
+ # http request via get
17
+ # @param [string] uri
18
+ # @return [Object] ruby representation of the json response
19
+ # if the reponsebody does not parse, returns
20
+ # the non-parsed body
21
+ def get(uri)
22
+ headers = { 'Content-Type' => 'application/json' }
23
+ res = Excon.get(@base_url + uri.to_s,
24
+ headers: headers,
25
+ user: username,
26
+ password: password,
27
+ ssl_verify_peer: false)
28
+ begin
29
+ access_check JSON(res.body)
30
+ rescue JSON::ParserError
31
+ res.body
32
+ end
33
+ end
34
+
35
+ # http request via get
36
+ # @param [string] uri
37
+ # @return [Integer, Object] http status and the ruby representation
38
+ # of the json response if the reponse body
39
+ # does not parse, returns the non-parsed body
40
+ def get_with_status(uri)
41
+ headers = { 'Content-Type' => 'application/json' }
42
+ res = Excon.get(@base_url + uri.to_s,
43
+ headers: headers,
44
+ user: username,
45
+ password: password,
46
+ ssl_verify_peer: false)
47
+ begin
48
+ data = access_check JSON(res.body)
49
+ return res.status, data
50
+
51
+ rescue JSON::ParserError
52
+ return res.status, res.body
53
+ end
54
+ end
55
+
56
+ # http request via post
57
+ # @param [string] uri
58
+ # @return [Object] ruby representation of the json response
59
+ # if the reponsebody does not parse, returns
60
+ # the non-parsed body
61
+ def post(uri, payload)
62
+ headers = { 'Content-Type' => 'application/json' }
63
+ res = Excon.post(@base_url + uri.to_s,
64
+ headers: headers,
65
+ user: username,
66
+ password: password,
67
+ ssl_verify_peer: false,
68
+ body: payload)
69
+ begin
70
+ access_check JSON(res.body)
71
+ rescue JSON::ParserError
72
+ res.body
73
+ end
74
+ end
75
+
76
+ # http request via put
77
+ # @param [string] uri
78
+ # @return [Object] ruby representation of the json response
79
+ # if the reponsebody does not parse, returns
80
+ # the non-parsed body
81
+ def put(uri, payload)
82
+ headers = { 'Content-Type' => 'application/json' }
83
+ res = Excon.put(@base_url + uri.to_s,
84
+ headers: headers,
85
+ user: username,
86
+ password: password,
87
+ ssl_verify_peer: false,
88
+ body: payload)
89
+ begin
90
+ access_check JSON(res.body)
91
+ rescue JSON::ParserError
92
+ res.body
93
+ end
94
+ end
95
+
96
+ # http request via delete
97
+ # @param [string] uri
98
+ # @return [Object] ruby representation of the json response
99
+ # if the reponsebody does not parse, returns
100
+ # the non-parsed body
101
+ def delete(uri)
102
+ headers = { 'Content-Type' => 'application/json' }
103
+ res = Excon.delete(@base_url + uri.to_s,
104
+ headers: headers,
105
+ user: username,
106
+ password: password,
107
+ ssl_verify_peer: false)
108
+ begin
109
+ access_check JSON(res.body)
110
+ rescue JSON::ParserError
111
+ res.body
112
+ end
113
+ end
114
+
115
+ # Throws an SFRest exception for requests that have problems
116
+ # @param [Object] data JSON parsed http reponse of the SFApi
117
+ # @return [Object] the data object if there are no issues
118
+ # @raise [SFRest::AccessDeniedError] if Authentication fails
119
+ # @raise [SFRest::ActionForbiddenError] if the users role cannot perform the request
120
+ # @raise [SFRest::BadRequestError] if there is something malformed in the request
121
+ #
122
+ def access_check(data)
123
+ return data unless data.is_a?(Hash) # if there is an error message, it will be in a hash.
124
+ unless data['message'].nil?
125
+ raise SFRest::AccessDeniedError, data['message'] if data['message'] =~ /Access denied/
126
+ raise SFRest::ActionForbiddenError, data['message'] if data['message'] =~ /Forbidden: /
127
+ raise SFRest::BadRequestError, data['message'] if data['message'] =~ /Bad Request:/
128
+ end
129
+ data
130
+ end
131
+
132
+ # pings the SF api as an authenticated user
133
+ # responds with a pong
134
+ def ping
135
+ get('/api/v1/ping')
136
+ end
137
+
138
+ # Pings to retrieve a service response.
139
+ def service_response
140
+ ping
141
+ end
142
+
143
+ # define the other class accessor methods.
144
+ # this will instantiate the class with the set creds
145
+ # and make it possible to do
146
+ # sfa = SFRest.new url, user, password
147
+ # sfa.ping
148
+ # sfa.site.first_site_id
149
+ #
150
+ # If a new class is added, add the accessor to this list.
151
+ # NOTE: accessor == Class_name.to_lower
152
+ REST_METHODS = %w(audit
153
+ backup
154
+ domains
155
+ group
156
+ role
157
+ site
158
+ stage
159
+ task
160
+ theme
161
+ update
162
+ user
163
+ variable).freeze
164
+
165
+ REST_METHODS.each do |m|
166
+ define_method(m) do
167
+ m.capitalize!
168
+ sfrest_klass = "SFRest::#{m}"
169
+ Object.const_get(sfrest_klass).new(self)
170
+ end
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,63 @@
1
+ module SFRest
2
+ # Find Staging envs and stage a set of sites
3
+ class Domains
4
+ # @param [SFRest::Connection] conn
5
+ def initialize(conn)
6
+ @conn = conn
7
+ end
8
+
9
+ # Get the domains information on a node
10
+ # @param [Integer] node_id The id of the node.
11
+ #
12
+ # @return [Hash] { "node_id" => 4966, "node_type" => "site",
13
+ # "time" => "2016-11-18T20:09:55+00:00",
14
+ # "domains" => { "protected_domains" =>[ "it252garden4.utest.sfdev.acquia-test.co" ],
15
+ # "custom_domains" => [ "it252coll3.utest.sfdev.acquia-test.co", "sc1.nikgregory.us" ] } }
16
+ def get(node_id)
17
+ current_path = "/api/v1/domains/#{node_id}"
18
+ @conn.get(current_path)
19
+ end
20
+
21
+ # Get the custom domains on a node
22
+ # @param [Integer] node_id The id of the node.
23
+ #
24
+ # @return [Array] custom(removable) domains on a node
25
+ def custom_domains(node_id)
26
+ get(node_id)['domains']['custom_domains']
27
+ end
28
+
29
+ # Get the protetect domains on a node
30
+ # @param [Integer] node_id The id of the node.
31
+ #
32
+ # @return [Array] protected (non-removable) domains on a node
33
+ def protected_domains(node_id)
34
+ get(node_id)['domains']['protected_domains']
35
+ end
36
+
37
+ # Add a domain
38
+ # @param [Integer] node_id The id of the node to which add a domain
39
+ # @param [String] domain_name domain to add. e.g. www.example.com
40
+ #
41
+ # @return [Hash] { "node_type": "site_collection",
42
+ # "domain": "www.example.com",
43
+ # "added": true,
44
+ # "messages": [ "Your domain name was successfully added to the site collection."] }
45
+ def add(node_id, domain_name)
46
+ payload = { 'domain_name' => domain_name }.to_json
47
+ @conn.post("/api/v1/domains/#{node_id}/add", payload)
48
+ end
49
+
50
+ # Remove a domain
51
+ # @param [Integer] node_id The id of the node to which remove a domain
52
+ # @param [String] domain_name domain to remove. e.g. www.example.com
53
+ #
54
+ # @return [Hash] { "node_type": "site_collection",
55
+ # "domain": "www.example.com",
56
+ # "removed": true,
57
+ # "messages": [ "Your domain name was successfully removed from the site collection." ] }
58
+ def remove(node_id, domain_name)
59
+ payload = { 'domain_name' => domain_name }.to_json
60
+ @conn.post("/api/v1/domains/#{node_id}/remove", payload)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,19 @@
1
+ module SFRest
2
+ # Error classes for SFRest
3
+
4
+ # Extends StandardError so we can catch SFRest::SFError
5
+ class SFError < StandardError; end
6
+
7
+ # Throw this when a user cannot successfuly authenticate
8
+ class AccessDeniedError < SFRest::SFError; end
9
+
10
+ # Throw this when a user does not have permission to perform an action
11
+ class ActionForbiddenError < SFRest::SFError; end
12
+
13
+ # Throw this when the request is incomplete or otherwise cannot be processed by
14
+ # the factory
15
+ class BadRequestError < SFRest::SFError; end
16
+
17
+ # Throw when a task appears to be running too long
18
+ class TaskNotDoneError < SFRest::SFError; end
19
+ end
@@ -0,0 +1,54 @@
1
+ module SFRest
2
+ # SF Group management
3
+ class Group
4
+ # @param [SFRest::Connection] conn
5
+ def initialize(conn)
6
+ @conn = conn
7
+ end
8
+
9
+ # Creates a site group with specified group name.
10
+ # This currently will only create a group in the root
11
+ # @param [String] groupname Name of the group to be created
12
+ def create_group(groupname)
13
+ current_path = '/api/v1/groups'
14
+ payload = { 'group_name' => groupname }.to_json
15
+ @conn.post(current_path, payload)
16
+ end
17
+
18
+ # Gets a site group with a specified group id.
19
+ # @param [Integer] group_id Id of the group to fetch
20
+ # @return [Hash] group object from the SF Api
21
+ def get_group(group_id = 0)
22
+ current_path = '/api/v1/groups/' << group_id.to_s
23
+ @conn.get(current_path)
24
+ end
25
+
26
+ # Gets a list of all site groups.
27
+ # @return [Hash] all the groups on the factory plus a count
28
+ # {'count' => count, 'groups' => Hash }
29
+ # this will iterate through the group pages
30
+ def group_list
31
+ page = 1
32
+ not_done = true
33
+ count = 0
34
+ while not_done
35
+ current_path = '/api/v1/groups?page=' << page.to_s
36
+ res = @conn.get(current_path)
37
+ if res['groups'] == []
38
+ not_done = false
39
+ elsif !res['message'].nil?
40
+ return { 'message' => res['message'] }
41
+ elsif page == 1
42
+ count = res['count']
43
+ groups = res['groups']
44
+ else
45
+ res['groups'].each do |group|
46
+ groups << group
47
+ end
48
+ end
49
+ page += 1
50
+ end
51
+ { 'count' => count, 'groups' => groups }
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,24 @@
1
+ module SFRest
2
+ # make a url querypath
3
+ # so that if the are multiple items in a get request
4
+ # we can get a path like /api/v1/foo?bar=boo&bat=gah ...
5
+ class Pathbuilder
6
+ # build a get query
7
+ # @param [String] current_path the uri like /api/v1/foo
8
+ # @param [Hash] datum k,v hash of get query param and value
9
+ def build_url_query(current_path, datum = nil)
10
+ unless datum.nil?
11
+ current_path += '?'
12
+ datum.each do |key, value|
13
+ current_path += '&' if needs_new_parameter? current_path
14
+ current_path += key.to_s + '=' + value.to_s
15
+ end
16
+ end
17
+ current_path
18
+ end
19
+
20
+ private def needs_new_parameter?(path)
21
+ path[-1, 1] != '?' # if path has '?' then we need to create a new parameter
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,101 @@
1
+ module SFRest
2
+ # create, delete, update, roles
3
+ class Role
4
+ # @param [SFRest::Connection] conn
5
+ def initialize(conn)
6
+ @conn = conn
7
+ end
8
+
9
+ # roles
10
+ # Gets the complete list of roles
11
+ # @return [Hash] all the roles on the factory plus a count
12
+ # {'count' => count, 'roles' => Hash }
13
+ # this will iterate through the roles pages
14
+ def role_list
15
+ page = 1
16
+ not_done = true
17
+ count = 0
18
+ while not_done
19
+ current_path = '/api/v1/roles?page=' << page.to_s
20
+ res = @conn.get(current_path)
21
+ if res['roles'] == []
22
+ not_done = false
23
+ elsif !res['message'].nil?
24
+ return { 'message' => res['message'] }
25
+ elsif page == 1
26
+ count = res['count']
27
+ roles = res['roles']
28
+ else
29
+ res['roles'].each do |roleid, rolename|
30
+ roles[roleid] = rolename
31
+ end
32
+ end
33
+ page += 1
34
+ end
35
+ { 'count' => count, 'roles' => roles }
36
+ end
37
+
38
+ # gets the role ID for the role named rolename
39
+ # will page through all the roles available searching for the site
40
+ # @param [String] rolename the name of the role to find
41
+ # @return [Integer] the id of rolename
42
+ # this will iterate through the roles pages
43
+ def get_role_id(rolename)
44
+ pglimit = 100
45
+ res = @conn.get('/api/v1/roles&limit=' + pglimit.to_s)
46
+ rolecount = res['count'].to_i
47
+ id = role_data_from_results(res, rolename)
48
+ return id if id
49
+ pages = (rolecount / pglimit) + 1
50
+ 2.upto(pages) do |i|
51
+ res = @conn.get('/api/v1/roles&limit=' + pglimit.to_s + '?page=' + i.to_s)
52
+ id = role_data_from_results(res, rolename)
53
+ return id if id
54
+ end
55
+ nil
56
+ end
57
+
58
+ # Extract the role data for rolename based on the role result object
59
+ # @param [Hash] res result from a request to /roles
60
+ # @param [String] rolename
61
+ # @return [Object] Integer, String, Array, Hash depending on the user data
62
+ def role_data_from_results(res, rolename)
63
+ roles = res['roles']
64
+ roles.each do |role|
65
+ return role[0].to_i if role[1] == rolename
66
+ end
67
+ nil
68
+ end
69
+
70
+ # Gets role data for a specific role id
71
+ # @param [Integer] id the role id
72
+ # @return [Hash] the role
73
+ def role_data(id)
74
+ @conn.get('/api/v1/roles/' + id.to_s)
75
+ end
76
+
77
+ # Creates a role.
78
+ # @param [String] name name of the role to create
79
+ def create_role(name)
80
+ current_path = '/api/v1/roles'
81
+ payload = { 'name' => name }.to_json
82
+ @conn.post(current_path, payload)
83
+ end
84
+
85
+ # Updates a role (changes the name).
86
+ # @param [Integer] id the id of the role to rename
87
+ # @param [String] name the new role name
88
+ def update_role(id, name)
89
+ current_path = "/api/v1/roles/#{id}/update"
90
+ payload = { 'new_name' => name }.to_json
91
+ @conn.put(current_path, payload)
92
+ end
93
+
94
+ # Delete a role.
95
+ # @param [Integer] id the role id of the role to delete
96
+ def delete_role(id)
97
+ current_path = "/api/v1/roles/#{id}"
98
+ @conn.delete(current_path)
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,99 @@
1
+ module SFRest
2
+ # Find sites, create a site,
3
+ class Site
4
+ # @param [SFRest::Connection] conn
5
+ def initialize(conn)
6
+ @conn = conn
7
+ end
8
+
9
+ # gets the site ID for the site named sitename
10
+ # will page through all the sites available searching for the site
11
+ # @param [String] sitename the name of the site
12
+ # @return [Integer] the id of sitename
13
+ def get_site_id(sitename)
14
+ pglimit = 100
15
+ res = @conn.get('/api/v1/sites&limit=' + pglimit.to_s)
16
+ sitecount = res['count'].to_i
17
+ id = site_data_from_results(res, sitename, 'id')
18
+ return id if id
19
+ pages = (sitecount / pglimit) + 1
20
+ 2.upto(pages) do |i|
21
+ res = @conn.get('/api/v1/sites&limit=' + pglimit.to_s + '?page=' + i.to_s)
22
+ id = site_data_from_results(res, sitename, 'id')
23
+ return id if id
24
+ end
25
+ nil
26
+ end
27
+
28
+ # Extract the site data for 'key' based on the site result object
29
+ # @param [Hash] res result from a request to /sites
30
+ # @param [String] sitename
31
+ # @param [String] key one of the user data returned (id, site, domain...)
32
+ # @return [Object] Integer, String, Array, Hash depending on the site data
33
+ def site_data_from_results(res, sitename, key)
34
+ sites = res['sites']
35
+ sites.each do |site|
36
+ return site[key] if site['site'] == sitename
37
+ end
38
+ nil
39
+ end
40
+
41
+ # Gets the site data for a specific site id
42
+ # @param [Integer] site_id the site id
43
+ # @return [Hash]
44
+ def get_site_data(site_id)
45
+ @conn.get('/api/v1/sites/' + site_id.to_s)
46
+ end
47
+
48
+ # gets the site id of the 1st one found using the api
49
+ # @return [Integer] the site id
50
+ def first_site_id
51
+ res = @conn.get('/api/v1/sites')
52
+ res['sites'].first['id']
53
+ end
54
+
55
+ # Gets the complete list of users
56
+ # Makes multiple requests to the factory to get all the sites on the factory
57
+ # @return [Hash{'count' => Integer, 'sites' => Hash}]
58
+ def site_list
59
+ page = 1
60
+ not_done = true
61
+ count = 0
62
+ while not_done
63
+ current_path = '/api/v1/sites?page=' << page.to_s
64
+ res = @conn.get(current_path)
65
+ if res['sites'] == []
66
+ not_done = false
67
+ elsif !res['message'].nil?
68
+ return { 'message' => res['message'] }
69
+ elsif page == 1
70
+ count = res['count']
71
+ sites = res['sites']
72
+ else
73
+ res['sites'].each do |site|
74
+ sites << site
75
+ end
76
+ end
77
+ page += 1
78
+ end
79
+ { 'count' => count, 'sites' => sites }
80
+ end
81
+
82
+ # Creates a site.
83
+ # @param [String] sitename The name of the site to create
84
+ # @param [Integer] group_id The Id of the group the site is to be a member of
85
+ # @param [String] install_profile The install profile to use when creating the site
86
+ def create_site(sitename, group_id, install_profile = nil)
87
+ current_path = '/api/v1/sites'
88
+ payload = { 'site_name' => sitename, 'group_ids' => [group_id],
89
+ 'install_profile' => install_profile }.to_json
90
+ @conn.post(current_path, payload)
91
+ end
92
+
93
+ # accessors for backups/restore
94
+ # so that you can do site.backup.list_backups
95
+ def backup
96
+ @conn.backup
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,31 @@
1
+ module SFRest
2
+ # Find Staging envs and stage a set of sites
3
+ class Stage
4
+ # @param [SFRest::Connection] conn
5
+ def initialize(conn)
6
+ @conn = conn
7
+ end
8
+
9
+ # Stage a site
10
+ # @param [String] to_env the name of of target env. defaults to test
11
+ # @param [Array] sites Array of site nids to stage
12
+ # @param [Boolean] email_site_status send an email about the staging status of each site
13
+ # @param [Boolean] skip_gardener skip staging the gardener and only stage the sites
14
+ #
15
+ # @return [Integer] Id of the staging task created.
16
+ def stage(to_env = 'test', sites = nil, email_site_status = false, skip_gardener = false)
17
+ payload = { 'to_env' => to_env, 'sites' => sites,
18
+ 'detailed_status' => email_site_status,
19
+ 'skip_gardener' => skip_gardener }.to_json
20
+ @conn.post('/api/v1/stage', payload)
21
+ end
22
+
23
+ # Query for available staging environments
24
+ #
25
+ # @return environments
26
+ def list_staging_environments
27
+ current_path = '/api/v1/stage'
28
+ @conn.get(current_path)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,261 @@
1
+ module SFRest
2
+ # Deal with tasks, find them, pause them...
3
+ class Task
4
+ STATUS_NOT_STARTED = 1 # Task has been added to queue but not picked up
5
+ STATUS_RESTARTED = 2 # Task has been re-added to the queue but not picked up
6
+ STATUS_TO_BE_RUN = 3 # Restarted + not started
7
+ STATUS_IN_PROCESS = 4 # A wip process is actively processing a task
8
+ STATUS_WAITING = 8 # Task has been released from active processing
9
+ STATUS_RUNNING = 12 # Running = in process + waiting to be processed
10
+ STATUS_COMPLETED = 16 # Task is successfully processed (exited with success)
11
+ STATUS_ERROR = 32 # Task unsccuessfully completed (exited with failure)
12
+ STATUS_KILLED = 64 # Task is terminated
13
+ STATUS_WARNING = 144 # Completed bit + 128 bit(warning).
14
+ STATUS_DONE = 240 # Completed + error + killed + 128 bit(warning)
15
+
16
+ # @param [SFRest::Connection] conn
17
+ def initialize(conn)
18
+ @conn = conn
19
+ end
20
+
21
+ # Returns true only if the status evaluates to completed
22
+ # @param [Integer] status
23
+ # @return [Boolean]
24
+ def status_completed?(status)
25
+ return true if status.to_i == STATUS_COMPLETED
26
+ false
27
+ end
28
+
29
+ # Returns true if the status evaluates to either
30
+ # waiting or in process
31
+ # @param [Integer] status
32
+ # @return [Boolean]
33
+ def status_running?(status)
34
+ return true if (status.to_i & STATUS_RUNNING) > 0
35
+ false
36
+ end
37
+
38
+ # Returns true only if the status evaluates to errored
39
+ # @param [Integer] status
40
+ # @return [Boolean]
41
+ def status_error?(status)
42
+ return true if status.to_i == STATUS_ERROR
43
+ false
44
+ end
45
+
46
+ # Returns true only if the status evaluates to killed
47
+ # @param [Integer] status
48
+ # @return [Boolean]
49
+ def status_killed?(status)
50
+ return true if status.to_i == STATUS_KILLED
51
+ false
52
+ end
53
+
54
+ # Returns true if the status evaluates to a state that is
55
+ # considered done
56
+ # @param [Integer] status
57
+ # @return [Boolean]
58
+ def status_done?(status)
59
+ return true if (status.to_i & STATUS_DONE) > 0
60
+ false
61
+ end
62
+
63
+ # Returns true only if WIP reports the status as running
64
+ # @param [Integer] task_id
65
+ # @return [Boolean]
66
+ def task_running?(task_id)
67
+ task_path = "/api/v1/wip/task/#{task_id}/status"
68
+
69
+ res = @conn.get task_path
70
+ status = res['wip_task']['status']
71
+ status_running?(status)
72
+ end
73
+
74
+ # Returns true only if WIP reports the status as completed
75
+ # @param [Integer] task_id
76
+ # @return [Boolean]
77
+ def task_completed?(task_id)
78
+ task_path = "/api/v1/wip/task/#{task_id}/status"
79
+
80
+ res = @conn.get task_path
81
+ status = res['wip_task']['status']
82
+ status_completed?(status)
83
+ end
84
+
85
+ # Returns true if WIP reports the status in a state that is
86
+ # considered done
87
+ # @param [Integer] task_id
88
+ # @return [Boolean]
89
+ def task_done?(task_id)
90
+ task_path = "/api/v1/wip/task/#{task_id}/status"
91
+
92
+ res = @conn.get task_path
93
+ status = res['wip_task']['status']
94
+ status_done?(status)
95
+ end
96
+
97
+ # Returns true only if WIP reports the status as killed
98
+ # @param [Integer] task_id
99
+ # @return [Boolean]
100
+ def task_killed?(task_id)
101
+ task_path = "/api/v1/wip/task/#{task_id}/status"
102
+
103
+ res = @conn.get task_path
104
+ status = res['wip_task']['status']
105
+ status_killed?(status)
106
+ end
107
+
108
+ # Returns true only if WIP reports the status as errored
109
+ # @param [Integer] task_id
110
+ # @return [Boolean]
111
+ def task_errored?(task_id)
112
+ task_path = "/api/v1/wip/task/#{task_id}/status"
113
+
114
+ res = @conn.get task_path
115
+ status = res['wip_task']['status']
116
+ status_error?(status)
117
+ end
118
+
119
+ # Find a set of task ids.
120
+ # @param [Integer] limit max amount of results to return per request
121
+ # @param [Integer] page page of request
122
+ # @param [String] group task group
123
+ # @param [String] klass task class
124
+ # @param [Integer] status Integerish the status of the task
125
+ # see SFRest::Task::STATUS_*
126
+ # @return [Array[Integer]]
127
+ def find_task_ids(limit = nil, page = nil, group = nil, klass = nil, status = nil)
128
+ res = find_tasks limit: limit, page: page, group: group, klass: klass, status: status
129
+ task_ids = []
130
+ i = 0
131
+ res.each do |task|
132
+ task_ids[i] = task['id']
133
+ i += 1
134
+ end
135
+ task_ids
136
+ end
137
+
138
+ # Find a set of tasks.
139
+ # @param [Hash] datum Hash of filters
140
+ # @option datum [Integer] :limit max amount of results to return per request
141
+ # @option datum [Integer] :page page of request
142
+ # @option datum [String] :group task group
143
+ # @option datum [String] :class task class
144
+ # @option datum [Integer] :status Integerish the status of the task
145
+ # see SFRest::Task::STATUS_*
146
+ def find_tasks(datum = nil)
147
+ current_path = '/api/v1/tasks'
148
+ pb = SFRest::Pathbuilder.new
149
+ @conn.get URI.parse(URI.encode(pb.build_url_query(current_path, datum))).to_s
150
+ end
151
+
152
+ # Looks for a task with a specific name
153
+ # @param [String] name display name of the task
154
+ # @param [String] group task group filter
155
+ # @param [String] klass task class filter
156
+ # @param [String] status task status filter
157
+ def get_task_id(name, group = nil, klass = nil, status = nil)
158
+ page_size = 100
159
+ page = 0
160
+ loop do
161
+ tasks = find_tasks(limit: page_size, page: page, group: group, class: klass, status: status)
162
+ tasks.each do |task|
163
+ return task['id'].to_i if task['name'] =~ /#{name}/
164
+ page += 1
165
+ end
166
+ break if tasks.size < page_size
167
+ end
168
+ nil
169
+ end
170
+
171
+ # Pauses all tasks.
172
+ def pause_all_tasks
173
+ current_path = '/api/v1/pause'
174
+ payload = { 'paused' => true }.to_json
175
+ @conn.post(current_path, payload)
176
+ end
177
+
178
+ # Resumes all tasks.
179
+ def resume_all_tasks
180
+ current_path = '/api/v1/pause'
181
+ payload = { 'paused' => false }.to_json
182
+ @conn.post(current_path, payload)
183
+ end
184
+
185
+ # Get a specific task's logs
186
+ # @param [Integer] task_id
187
+ def get_task_logs(task_id)
188
+ current_path = '/api/v1/tasks/' << task_id.to_s << '/logs'
189
+ @conn.get(current_path)
190
+ end
191
+
192
+ # Gets the value of a vairable
193
+ # @TODO: this is missnamed becasue it does not check the global paused variable
194
+ # @param [String] variable_name
195
+ # @return [Object]
196
+ def globally_paused?(variable_name)
197
+ current_path = "/api/v1/variables?name=#{variable_name}"
198
+ res = @conn.get(current_path)
199
+ res[variable_name]
200
+ end
201
+
202
+ # Pauses a specific task identified by its task id.
203
+ # This can pause either the task and it's children or just the task
204
+ # @param [Integer] task_id
205
+ # @param [String] level family|task
206
+ def pause_task(task_id, level = 'family')
207
+ current_path = '/api/v1/pause/' << task_id.to_s
208
+ payload = { 'paused' => true, 'level' => level }.to_json
209
+ @conn.post(current_path, payload)
210
+ end
211
+
212
+ # Resumes a specific task identified by its task id.
213
+ # This can resume either the task and it's children or just the task
214
+ # @param [Integer] task_id
215
+ # @param [String] level family|task
216
+ def resume_task(task_id, level = 'family')
217
+ current_path = '/api/v1/pause/' << task_id.to_s
218
+ payload = { 'paused' => false, 'level' => level }.to_json
219
+ @conn.post(current_path, payload)
220
+ end
221
+
222
+ # returns the classes that are either softpaused or softpause-for-update
223
+ # @param [String] type softpaused | softpause-for-update
224
+ # @return [Array] Array of wip classes
225
+ def get_task_class_info(type = '')
226
+ current_path = '/api/v1/classes/' << type
227
+ @conn.get(current_path)
228
+ end
229
+
230
+ # Get the status of a wip task by id.
231
+ # @param [Integer] task_id
232
+ # @return [Hash{"wip_task" => {"id" => Integer, "status" => Integer}, "time" => timestamp}]
233
+ def get_wip_task_status(task_id)
234
+ current_path = "/api/v1/wip/task/#{task_id}/status"
235
+ @conn.get(current_path)
236
+ end
237
+
238
+ # Blocks until a task is done
239
+ # @param [Integer] task_id
240
+ # @param [Integer] max_nap seconds to try before giving up
241
+ def wait_until_done(task_id, max_nap = 600)
242
+ wait_until_state(task_id, 'done', max_nap)
243
+ end
244
+
245
+ # Blocks until a task reaches a specific status
246
+ # @param [Integer] task_id
247
+ # @param [String] state state to reach
248
+ # @param [Integer] max_nap seconds to try before giving up
249
+ def wait_until_state(task_id, state, max_nap)
250
+ blink_time = 5 # wake up and scan
251
+ nap_start = Time.now
252
+ state_method = method("task_#{state}?".to_sym)
253
+ loop do
254
+ break if state_method.call(task_id)
255
+ raise TaskNotDoneError, "Task: #{task_id} has taken too long to complete!" if Time.new > (nap_start + max_nap)
256
+ sleep blink_time
257
+ end
258
+ task_id
259
+ end
260
+ end
261
+ end
@@ -0,0 +1,23 @@
1
+ module SFRest
2
+ # Tell the Factory that there is theme work to do
3
+ class Theme
4
+ # @param [SFRest::Connection] conn
5
+ def initialize(conn)
6
+ @conn = conn
7
+ end
8
+
9
+ # Sends a theme notification.
10
+ def send_theme_notification(scope = 'site', event = 'modify', nid = 0, theme = '')
11
+ current_path = '/api/v1/theme/notification'
12
+ payload = { 'scope' => scope, 'event' => event, 'nid' => nid, 'theme' => theme }.to_json
13
+ @conn.post(current_path, payload)
14
+ end
15
+
16
+ # Processes a theme notification.
17
+ def process_theme_notification(sitegroup_id = 0)
18
+ current_path = '/api/v1/theme/process'
19
+ payload = { 'sitegroup_id' => sitegroup_id }.to_json
20
+ @conn.post(current_path, payload)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,78 @@
1
+ module SFRest
2
+ # Drive updates on the Site Factory
3
+ class Update
4
+ # @param [SFRest::Connection] conn
5
+ def initialize(conn)
6
+ @conn = conn
7
+ end
8
+
9
+ # Gets the status information.
10
+ def status_info
11
+ current_path = '/api/v1/status'
12
+ @conn.get(current_path)
13
+ end
14
+
15
+ # Modifies the status information.
16
+ def modify_status(site_creation, site_duplication, domain_management, bulk_operations)
17
+ current_path = '/api/v1/status'
18
+ payload = { 'site_creation' => site_creation,
19
+ 'site_duplication' => site_duplication,
20
+ 'domain_management' => domain_management,
21
+ 'bulk_operations' => bulk_operations }.to_json
22
+ @conn.put(current_path, payload)
23
+ end
24
+
25
+ # Lists vcs refs.
26
+ def list_vcs_refs(type = 'sites')
27
+ current_path = '/api/v1/vcs?type=' << type
28
+ @conn.get(current_path)
29
+ end
30
+
31
+ # Starts an update.
32
+ def start_update(ref)
33
+ update_data = { scope: 'sites', sites_type: 'code, db', sites_ref: ref }
34
+ update(update_data)
35
+ end
36
+
37
+ # Starts an update. The rest api supports the following
38
+ # scope: sites|factory|both (defaults to 'sites')
39
+ # start_time:
40
+ # sites_type: code|code, db| code, db, registry (defaults to 'code, db')
41
+ # factory_type: code|code, db (defaults to 'code, db')
42
+ # sites_ref:
43
+ # factory_ref:
44
+ # This method does not filter or validate so that it can be used for
45
+ # negative cases. (missing data)
46
+ def update(datum)
47
+ current_path = '/api/v1/update'
48
+ payload = datum.to_json
49
+ @conn.post(current_path, payload)
50
+ end
51
+
52
+ # Gets the list of updates.
53
+ def update_list
54
+ current_path = '/api/v1/update'
55
+ @conn.get(current_path)
56
+ end
57
+
58
+ # Gets the progress of an update by id.
59
+ def update_progress(update_id)
60
+ current_path = '/api/v1/update/' + update_id.to_s + '/status'
61
+ @conn.get(current_path)
62
+ end
63
+
64
+ # Pauses current update.
65
+ def pause_update
66
+ current_path = '/api/v1/update/pause'
67
+ payload = { 'pause' => true }.to_json
68
+ @conn.post(current_path, payload)
69
+ end
70
+
71
+ # Resumes current update.
72
+ def resume_update
73
+ current_path = '/api/v1/update/pause'
74
+ payload = { 'pause' => false }.to_json
75
+ @conn.post(current_path, payload)
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,106 @@
1
+ module SFRest
2
+ # Do User actions within the Site Factory
3
+ class User
4
+ # @param [SFRest::Connection] conn
5
+ def initialize(conn)
6
+ @conn = conn
7
+ end
8
+
9
+ # Gets the complete list of users
10
+ # Makes multiple requests to the factory to get all the users on the factory
11
+ # @return [Hash{'count' => Integer, 'users' => Hash}]
12
+ def user_list
13
+ page = 1
14
+ not_done = true
15
+ count = 0
16
+ while not_done
17
+ current_path = '/api/v1/users?page=' << page.to_s
18
+ res = @conn.get(current_path)
19
+ if res['users'] == []
20
+ not_done = false
21
+ elsif !res['message'].nil?
22
+ return { 'message' => res['message'] }
23
+ elsif page == 1
24
+ count = res['count']
25
+ users = res['users']
26
+ else
27
+ res['users'].each do |user|
28
+ users << user
29
+ end
30
+ end
31
+ page += 1
32
+ end
33
+ { 'count' => count, 'users' => users }
34
+ end
35
+
36
+ # gets the site ID for the site named sitename
37
+ # will page through all the sites available searching for the site
38
+ # @param [String] username drupal username (not email)
39
+ # @return [Integer] the uid of the drupal user
40
+ def get_user_id(username)
41
+ pglimit = 100
42
+ res = @conn.get('/api/v1/users&limit=' + pglimit.to_s)
43
+ usercount = res['count'].to_i
44
+ id = user_data_from_results(res, username, 'uid')
45
+ return id if id
46
+ pages = (usercount / pglimit) + 1
47
+ 2.upto(pages) do |i|
48
+ res = @conn.get('/api/v1/users&limit=' + pglimit.to_s + '?page=' + i.to_s)
49
+ id = user_data_from_results(res, username, 'uid')
50
+ return id if id
51
+ end
52
+ nil
53
+ end
54
+
55
+ # Extract the user data for 'key' based on the user result object
56
+ # @param [Hash] res result from a request to /users
57
+ # @param [String] username
58
+ # @param [String] key one of the user data returned (uid, mail, tfa_status...)
59
+ # @return [Object] Integer, String, Array, Hash depending on the user data
60
+ def user_data_from_results(res, username, key)
61
+ users = res['users']
62
+ users.each do |user|
63
+ return user[key] if user['name'] == username
64
+ end
65
+ nil
66
+ end
67
+
68
+ # Gets the data for user UID
69
+ # @param [int] uid site id
70
+ # @return [Hash]
71
+ def get_user_data(uid)
72
+ @conn.get('/api/v1/users/' + uid.to_s)
73
+ end
74
+
75
+ # Creates a user.
76
+ # @param [String] name
77
+ # @param [String] email
78
+ # @param [Hash] datum hash with elements :pass => string,
79
+ # :status => 0|1,
80
+ # :roles => Array
81
+ def create_user(name, email, datum = nil)
82
+ current_path = '/api/v1/users'
83
+ payload = { name: name, mail: email }
84
+ payload.merge!(datum) unless datum.nil?
85
+ @conn.post(current_path, payload.to_json)
86
+ end
87
+
88
+ # Updates a user.
89
+ # @param [Integer] uid user id of the drupal user to update
90
+ # @param [Hash] datum hash with elements :name => string, :pass => string,
91
+ # :status => 0|1, :roles => Array,
92
+ # :mail => string@string, :tfa_status => 0|1
93
+ def update_user(uid, datum = nil)
94
+ current_path = "/api/v1/users/#{uid}/update"
95
+ payload = datum.to_json unless datum.nil?
96
+ @conn.put(current_path, payload)
97
+ end
98
+
99
+ # Delete a user.
100
+ # @param [integer] uid Uid of the user to be deleted
101
+ def delete_user(uid)
102
+ current_path = "/api/v1/users/#{uid}"
103
+ @conn.delete(current_path)
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,28 @@
1
+ module SFRest
2
+ # Perform actions against variables in the Factory
3
+ class Variable
4
+ # @param [SFRest::Connection] conn
5
+ def initialize(conn)
6
+ @conn = conn
7
+ end
8
+
9
+ # Gets the list of variables.
10
+ def variable_list
11
+ current_path = '/api/v1/variables'
12
+ @conn.get(current_path)
13
+ end
14
+
15
+ # Gets the value of a specific variable.
16
+ def get_variable(name)
17
+ current_path = '/api/v1/variables?name=' << name
18
+ @conn.get(current_path)
19
+ end
20
+
21
+ # Sets the key and value of a variable.
22
+ def set_variable(name, value)
23
+ current_path = '/api/v1/variables'
24
+ payload = { 'name' => name, 'value' => value }.to_json
25
+ @conn.put(current_path, payload)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ module SFRest
2
+ VERSION = '0.0.8'.freeze
3
+ end
data/lib/sfrest.rb ADDED
@@ -0,0 +1,43 @@
1
+ # Simple wrappper around RestClient.Resource
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__)) unless
3
+ $LOAD_PATH.include?(File.dirname(__FILE__)) ||
4
+ $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
5
+
6
+ require 'excon'
7
+ require 'json'
8
+
9
+ require 'sfrest/audit'
10
+ require 'sfrest/backup'
11
+ require 'sfrest/connection'
12
+ require 'sfrest/domains'
13
+ require 'sfrest/error'
14
+ require 'sfrest/group'
15
+ require 'sfrest/pathbuilder'
16
+ require 'sfrest/role'
17
+ require 'sfrest/site'
18
+ require 'sfrest/stage'
19
+ require 'sfrest/task'
20
+ require 'sfrest/theme'
21
+ require 'sfrest/update'
22
+ require 'sfrest/user'
23
+ require 'sfrest/variable'
24
+
25
+ # Base Class for SF rest API sdk
26
+ module SFRest
27
+ # Class set to work as an sdk for the Site Factory Rest api
28
+ # most of the interesting pieces happen in the connection class and others
29
+ class << self
30
+ attr_accessor :base_url, :user, :password, :conn
31
+
32
+ # returns a connection object to the SF Rest api for a specific factory
33
+ # @param [String] url Base url of the Site Factory
34
+ # @param [String] user username of a user on the factory
35
+ # @param [String] password api password for the user on the factory
36
+ def new(url, user, password)
37
+ @base_url = url
38
+ @user = user
39
+ @password = password
40
+ @conn = SFRest::Connection.new(@base_url, @user, @password)
41
+ end
42
+ end
43
+ end
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sfrest
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.8
5
+ platform: ruby
6
+ authors:
7
+ - ACSF Engineering
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-12-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: excon
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.11'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.11'
69
+ - !ruby/object:Gem::Dependency
70
+ name: webmock
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.24'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.24'
83
+ description: Wrapper methods around the ACSF Rest API.
84
+ email:
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files: []
88
+ files:
89
+ - lib/sfrest.rb
90
+ - lib/sfrest/audit.rb
91
+ - lib/sfrest/backup.rb
92
+ - lib/sfrest/connection.rb
93
+ - lib/sfrest/domains.rb
94
+ - lib/sfrest/error.rb
95
+ - lib/sfrest/group.rb
96
+ - lib/sfrest/pathbuilder.rb
97
+ - lib/sfrest/role.rb
98
+ - lib/sfrest/site.rb
99
+ - lib/sfrest/stage.rb
100
+ - lib/sfrest/task.rb
101
+ - lib/sfrest/theme.rb
102
+ - lib/sfrest/update.rb
103
+ - lib/sfrest/user.rb
104
+ - lib/sfrest/variable.rb
105
+ - lib/sfrest/version.rb
106
+ homepage: http://github.com/acquia/sf-sdk-ruby
107
+ licenses:
108
+ - MIT
109
+ metadata: {}
110
+ post_install_message:
111
+ rdoc_options: []
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 2.5.1
127
+ signing_key:
128
+ specification_version: 4
129
+ summary: Acquia Site Factory Rest API.
130
+ test_files: []