Class: JenkinsApi::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/jenkins_api_client/client.rb,
lib/jenkins_api_client/job.rb,
lib/jenkins_api_client/node.rb,
lib/jenkins_api_client/user.rb,
lib/jenkins_api_client/view.rb,
lib/jenkins_api_client/system.rb,
lib/jenkins_api_client/version.rb,
lib/jenkins_api_client/build_queue.rb

Overview

This is the client class that acts as the bridge between the subclasses and Jnekins. This class contains methods that performs GET and POST requests for various operations.

Defined Under Namespace

Classes: BuildQueue, Job, Node, System, User, View

Constant Summary collapse

DEFAULT_SERVER_PORT =

Default port to be used to connect to Jenkins

8080
DEFAULT_TIMEOUT =

Default timeout in seconds to be used while performing operations

120
VALID_PARAMS =

Parameters that are permitted as options while initializing the client

[
  "server_url",
  "server_ip",
  "server_port",
  "proxy_ip",
  "proxy_port",
  "jenkins_path",
  "username",
  "password",
  "password_base64",
  "log_location",
  "log_level",
  "timeout",
  "ssl",
  "follow_redirects",
  "identity_file"
].freeze
MAJOR =

Major version of the gem

0
MINOR =

Minor version of the gem

14
TINY =

Tiny version of the gem used for patches

1
PRE =

Used for pre-releases

nil
VERSION =

Version String of Jenkins API Client.

[MAJOR, MINOR, TINY, PRE].compact.join('.')

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(args) ⇒ JenkinsApi::Client

Initialize a Client object with Jenkins CI server credentials

Parameters:

  • args (Hash)

    Arguments to connect to Jenkins server

Options Hash (args):

  • :server_ip (String)

    the IP address of the Jenkins CI server

  • :server_port (String)

    the port on which the Jenkins listens

  • :server_url (String)

    the full URL address of the Jenkins CI server (http/https)

  • :username (String)

    the username used for connecting to the server (optional)

  • :password (String)

    the password for connecting to the CI server (optional)

  • :password_base64 (String)

    the password with base64 encoded format for connecting to the CI server (optional)

  • :identity_file (String)

    the priviate key file for Jenkins CLI authentication, it is used only for executing CLI commands. also remember to upload the public key to http://<Server IP>:<Server Port>/user/<Username>/configure

  • :proxy_ip (String)

    the proxy IP address

  • :proxy_port (String)

    the proxy port

  • :jenkins_path (String) — default: "/"

    the optional context path for Jenkins

  • :ssl (Boolean) — default: false

    indicates if Jenkins is accessible over HTTPS

  • :follow_redirects (Boolean)

    This argument causes the client to follow a redirect (jenkins can return a 30x when starting a build)

  • :timeout (Fixnum) — default: 120

    This argument sets the timeout for operations that take longer (in seconds)

  • :log_location (String) — default: STDOUT

    The location for the log file

  • :log_level (Fixnum) — default: Logger::INFO

    The level for messages to be logged. Should be one of: Logger::DEBUG (0), Logger::INFO (1), Logger::WARN (2), Logger::ERROR (2), Logger::FATAL (3) (Defaults to Logger::INFO)

Raises:

  • (ArgumentError)

    when required options are not provided.



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/jenkins_api_client/client.rb', line 113

def initialize(args)
  args.each do |key, value|
    if value && VALID_PARAMS.include?(key.to_s)
      instance_variable_set("@#{key}", value)
    end
  end if args.is_a? Hash

  # Server IP or Server URL must be specifiec
  unless @server_ip || @server_url
    raise ArgumentError, "Server IP or Server URL is required to connect" +
      " to Jenkins"
  end

  # Username/password are optional as some jenkins servers do not require
  # authentication
  if @username && !(@password || @password_base64)
    raise ArgumentError, "If username is provided, password is required"
  end
  if @proxy_ip.nil? ^ @proxy_port.nil?
    raise ArgumentError, "Proxy IP and port must both be specified or" +
      " both left nil"
  end

  # Get info from the server_url, if we got one
  if @server_url
    server_uri = URI.parse(@server_url)
    @server_ip = server_uri.host
    @server_port = server_uri.port
    @ssl = server_uri.scheme == "https"
    @jenkins_path = server_uri.path
  end

  @jenkins_path ||= ""
  @jenkins_path.gsub!(/\/$/,"") # remove trailing slash if there is one
  @server_port = DEFAULT_SERVER_PORT unless @server_port
  @timeout = DEFAULT_TIMEOUT unless @timeout
  @ssl ||= false

  # Setting log options
  @log_location = STDOUT unless @log_location
  @log_level = Logger::INFO unless @log_level
  @logger = Logger.new(@log_location)
  @logger.level = @log_level


  # Base64 decode inserts a newline character at the end. As a workaround
  # added chomp to remove newline characters. I hope nobody uses newline
  # characters at the end of their passwords :)
  @password = Base64.decode64(@password_base64).chomp if @password_base64

  # No connections are made to the Jenkins server during initialize to
  # allow the unit tests to behave normally as mocking is simpler this way.
  # If this variable is nil, the first POST request will query the API and
  # populate this variable.
  @crumbs_enabled = nil
  # The crumbs hash. Store it so that we don't have to obtain the crumb for
  # every POST request. It appears that the crumb doesn't change often.
  @crumb = {}
  # This is the number of times to refetch the crumb if it ever expires.
  @crumb_max_retries = 3
end

Instance Attribute Details

#loggerObject

Returns the value of attribute logger.



42
43
44
# File 'lib/jenkins_api_client/client.rb', line 42

def logger
  @logger
end

#timeoutObject

Returns the value of attribute timeout.



42
43
44
# File 'lib/jenkins_api_client/client.rb', line 42

def timeout
  @timeout
end

Instance Method Details

#api_get_request(url_prefix, tree = nil, url_suffix = "/api/json", raw_response = false) ⇒ String, JSON

Sends a GET request to the Jenkins CI server with the specified URL

Parameters:

  • url_prefix (String)

    The prefix to use in the URL

  • tree (String) (defaults to: nil)

    A specific JSON tree to optimize the API call

  • url_suffix (String) (defaults to: "/api/json")

    The suffix to be used in the URL

  • raw_response (Boolean) (defaults to: false)

    Return complete Response object instead of JSON body of response

Returns:

  • (String, JSON)

    JSON response from Jenkins



306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/jenkins_api_client/client.rb', line 306

def api_get_request(url_prefix, tree = nil, url_suffix ="/api/json",
                    raw_response = false)
  url_prefix = "#{@jenkins_path}#{url_prefix}"
  to_get = ""
  if tree
    to_get = "#{url_prefix}#{url_suffix}?#{tree}"
  else
    to_get = "#{url_prefix}#{url_suffix}"
  end
  to_get = URI.escape(to_get)
  request = Net::HTTP::Get.new(to_get)
  @logger.info "GET #{to_get}"
  response = make_http_request(request)
  if raw_response
    handle_exception(response, "raw")
  else
    handle_exception(response, "body", url_suffix =~ /json/)
  end
end

#api_post_request(url_prefix, form_data = {}, raw_response = false) ⇒ String

Sends a POST message to the Jenkins CI server with the specified URL

Parameters:

  • url_prefix (String)

    The prefix to be used in the URL

  • form_data (Hash) (defaults to: {})

    Form data to send with POST request

Returns:

  • (String)

    Response code form Jenkins Response



333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
# File 'lib/jenkins_api_client/client.rb', line 333

def api_post_request(url_prefix, form_data = {}, raw_response = false)
  retries = @crumb_max_retries
  begin
    refresh_crumbs

    # Added form_data default {} instead of nil to help with proxies
    # that barf with empty post
    url_prefix = URI.escape("#{@jenkins_path}#{url_prefix}")
    request = Net::HTTP::Post.new("#{url_prefix}")
    @logger.info "POST #{url_prefix}"
    request.content_type = 'application/json'
    if @crumbs_enabled
      request[@crumb["crumbRequestField"]] = @crumb["crumb"]
    end
    request.set_form_data(form_data)
    response = make_http_request(request)
    if raw_response
      handle_exception(response, "raw")
    else
      handle_exception(response)
    end
  rescue Exceptions::ForbiddenException => e
    refresh_crumbs(true)

    if @crumbs_enabled
      @logger.info "Retrying: #{@crumb_max_retries - retries + 1} out of" +
        " #{@crumb_max_retries} times..."
      retries -= 1

      if retries > 0
        retry
      else
        raise Exceptions::ForbiddenWithCrumb.new(@logger, e.message)
      end
    else
      raise
    end
  end
end

#exec_cli(command, args = []) ⇒ String

Execute the Jenkins CLI

Parameters:

  • command (String)

    command name

  • args (Array) (defaults to: [])

    the arguments for the command

Returns:

  • (String)

    command output from the CLI

Raises:



484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
# File 'lib/jenkins_api_client/client.rb', line 484

def exec_cli(command, args = [])
  base_dir = File.dirname(__FILE__)
  server_url = "http://#{@server_ip}:#{@server_port}/#{@jenkins_path}"
  cmd = "java -jar #{base_dir}/../../java_deps/jenkins-cli.jar -s #{server_url}"
  cmd << " -i #{@identity_file}" if @identity_file && !@identity_file.empty?
  cmd << " #{command}"
  cmd << " --username #{@username} --password #{@password}" if @identity_file.nil? || @identity_file.empty?
  cmd << ' '
  cmd << args.join(' ')
  java_cmd = Mixlib::ShellOut.new(cmd)

  # Run the command
  java_cmd.run_command
  if java_cmd.stderr.empty?
    java_cmd.stdout.chomp
  else
    # The stderr has a stack trace of the Java program. We'll already have
    # a stack trace for Ruby. So just display a descriptive message for the
    # error thrown by the CLI.
    raise Exceptions::CLIException.new(
      @logger,
      java_cmd.stderr.split("\n").first
    )
  end
end

#get_config(url_prefix) ⇒ String

Obtains the configuration of a component from the Jenkins CI server

Parameters:

  • url_prefix (String)

    The prefix to be used in the URL

Returns:

  • (String)

    XML configuration obtained from Jenkins



379
380
381
382
383
384
385
# File 'lib/jenkins_api_client/client.rb', line 379

def get_config(url_prefix)
  url_prefix = URI.escape("#{@jenkins_path}#{url_prefix}")
  request = Net::HTTP::Get.new("#{url_prefix}/config.xml")
  @logger.info "GET #{url_prefix}/config.xml"
  response = make_http_request(request)
  handle_exception(response, "body")
end

#get_hudson_versionString

Obtain the Hudson version of the CI server

Returns:

  • (String)

    Version of Hudson on Jenkins server



460
461
462
463
# File 'lib/jenkins_api_client/client.rb', line 460

def get_hudson_version
  response = get_root
  response["X-Hudson"]
end

#get_jenkins_versionObject

Obtains the jenkins version from the API

Returns:

  • Jenkins version



451
452
453
454
# File 'lib/jenkins_api_client/client.rb', line 451

def get_jenkins_version
  response = get_root
  response["X-Jenkins"]
end

#get_rootNet::HTTP::Response

Obtains the root of Jenkins server. This function is used to see if Jenkins is running

Returns:

  • (Net::HTTP::Response)

    Response from Jenkins for “/”



290
291
292
293
294
# File 'lib/jenkins_api_client/client.rb', line 290

def get_root
  @logger.info "GET /"
  request = Net::HTTP::Get.new("/")
  make_http_request(request)
end

#get_server_dateString

Obtain the date of the Jenkins server

Returns:

  • (String)

    Server date



469
470
471
472
# File 'lib/jenkins_api_client/client.rb', line 469

def get_server_date
  response = get_root
  response["Date"]
end

#inspectObject

Overrides the inspect method to get rid of the credentials being shown in the in interactive IRB sessions and also when the ‘inspect` method is called. Just print the important variables.



235
236
237
238
239
240
241
242
243
244
# File 'lib/jenkins_api_client/client.rb', line 235

def inspect
  "#<JenkinsApi::Client:0x#{(self.__id__ * 2).to_s(16)}" +
    " @ssl=#{@ssl.inspect}," +
    " @log_location=#{@log_location.inspect}," +
    " @log_level=#{@log_level.inspect}," +
    " @crumbs_enabled=#{@crumbs_enabled.inspect}," +
    " @follow_redirects=#{@follow_redirects.inspect}," +
    " @jenkins_path=#{@jenkins_path.inspect}," +
    " @timeout=#{@timeout.inspect}>"
end

#jobJenkinsApi::Client::Job

Creates an instance to the Job class by passing a reference to self

Returns:



179
180
181
# File 'lib/jenkins_api_client/client.rb', line 179

def job
  JenkinsApi::Client::Job.new(self)
end

#nodeJenkinsApi::Client::Node

Creates an instance to the Node class by passing a reference to self

Returns:



195
196
197
# File 'lib/jenkins_api_client/client.rb', line 195

def node
  JenkinsApi::Client::Node.new(self)
end

#post_config(url_prefix, xml) ⇒ String

Posts the given xml configuration to the url given

Parameters:

  • url_prefix (String)

    The prefix to be used in the URL

  • xml (String)

    The XML configuration to be sent to Jenkins

Returns:

  • (String)

    Response code returned from Jenkins



394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
# File 'lib/jenkins_api_client/client.rb', line 394

def post_config(url_prefix, xml)
  retries = @crumb_max_retries
  begin
    refresh_crumbs

    url_prefix = URI.escape("#{@jenkins_path}#{url_prefix}")
    request = Net::HTTP::Post.new("#{url_prefix}")
    @logger.info "POST #{url_prefix}"
    request.body = xml
    request.content_type = 'application/xml'
    if @crumbs_enabled
      request[@crumb["crumbRequestField"]] = @crumb["crumb"]
    end
    response = make_http_request(request)
    handle_exception(response)
  rescue Exceptions::ForbiddenException => e
    refresh_crumbs(true)

    if @crumbs_enabled
      @logger.info "Retrying: #{@crumb_max_retries - retries + 1} out of" +
        " #{@crumb_max_retries} times..."
      retries -= 1

      if retries > 0
        retry
      else
        raise Exceptions::ForbiddenWithCrumb.new(@logger, e.message)
      end
    else
      raise
    end
  end
end

#queueJenkinsApi::Client::BuildQueue

Creates an instance to the BuildQueue by passing a reference to self

Returns:



211
212
213
# File 'lib/jenkins_api_client/client.rb', line 211

def queue
  JenkinsApi::Client::BuildQueue.new(self)
end

#systemJenkinsApi::Client::System

Creates an instance to the System class by passing a reference to self

Returns:



187
188
189
# File 'lib/jenkins_api_client/client.rb', line 187

def system
  JenkinsApi::Client::System.new(self)
end

#to_sString

Returns a string representing the class name

Returns:

  • (String)

    string representation of class name



227
228
229
# File 'lib/jenkins_api_client/client.rb', line 227

def to_s
  "#<JenkinsApi::Client>"
end

#use_crumbs?Boolean

Checks if Jenkins uses crumbs (i.e) the XSS disable option is checked in Jenkins’ security settings

Returns:

  • (Boolean)

    whether Jenkins uses crumbs or not



433
434
435
436
# File 'lib/jenkins_api_client/client.rb', line 433

def use_crumbs?
  response = api_get_request("")
  response["useCrumbs"]
end

#use_security?Boolean

Checks if Jenkins uses security

Returns:

  • (Boolean)

    whether Jenkins uses security or not



442
443
444
445
# File 'lib/jenkins_api_client/client.rb', line 442

def use_security?
  response = api_get_request("")
  response["useSecurity"]
end

#userJenkinsApi::Client::User

Creates an instance of the User class by passing a reference to self

Returns:



219
220
221
# File 'lib/jenkins_api_client/client.rb', line 219

def user
  JenkinsApi::Client::User.new(self)
end

#viewJenkinsApi::Client::View

Creates an instance to the View class by passing a reference to self

Returns:



203
204
205
# File 'lib/jenkins_api_client/client.rb', line 203

def view
  JenkinsApi::Client::View.new(self)
end