def request(http_method: :get, path:'/', body: nil, query: {}, headers: {}, response_block: nil, expects: [200, 201, 204], host: nil, port: nil, auth: true, gzip: true)

      retried ||= false

      if auth && token_expired?
        raise Excon::Error::Unauthorized, "Token expired or not valid, you need to login again, use: kontena #{token_is_for_master? ? "master" : "cloud"} login"
      end

      request_headers = request_headers(headers, auth: auth, gzip: gzip)

      if body.nil?
        body_content = ''
        request_headers.delete(CONTENT_TYPE)
      else
        body_content =  encode_body(body, request_headers[CONTENT_TYPE])
        request_headers.merge!('Content-Length' => body_content.bytesize)
      end

      uri = URI.parse(path)
      host_options = {}

      if uri.host
        host_options[:host]   = uri.host
        host_options[:port]   = uri.port
        host_options[:scheme] = uri.scheme
        path                  = uri.request_uri
      else
        host_options[:host] = host if host
        host_options[:port] = port if port
      end

      request_options = {
          method: http_method,
          expects: Array(expects),
          path: path_with_prefix(path),
          headers: request_headers,
          body: body_content,
          query: query
      }.merge(host_options)

      request_options.merge!(response_block: response_block) if response_block

      # Store the response into client.last_response
      @last_response = http_client.request(request_options)

      parse_response(@last_response)
    rescue Excon::Error::Unauthorized
      if token
        debug { 'Server reports access token expired' }

        if retried || !token || !token['refresh_token']
          raise Kontena::Errors::StandardError.new(401, 'The access token has expired and needs to be refreshed')
        end

        retried = true
        retry if refresh_token
      end
      raise Kontena::Errors::StandardError.new(401, 'Unauthorized')
    rescue Excon::Error::HTTPStatus => error
      if error.response.headers['Content-Encoding'] == 'gzip'
        error.response.body = Zlib::GzipReader.new(StringIO.new(error.response.body)).read
      end

      debug { "Request #{error.request[:method].upcase} #{error.request[:path]}: #{error.response.status} #{error.response.reason_phrase}: #{error.response.body}" }

      handle_error_response(error.response)
    end
def request(http_method: :get, path:'/', body: nil, query: {}, headers: {}, response_block: nil, expects: [200, 201, 204], host: nil, port: nil, auth: true, gzip: true)

      retried ||= false

      if auth && token_expired?
        raise Excon::Error::Unauthorized, "Token expired or not valid, you need to login again, use: kontena #{token_is_for_master? ? "master" : "cloud"} login"
      end

      request_headers = request_headers(headers, auth: auth, gzip: gzip)

      if body.nil?
        body_content = ''
        request_headers.delete(CONTENT_TYPE)
      else
        body_content =  encode_body(body, request_headers[CONTENT_TYPE])
        request_headers.merge!('Content-Length' => body_content.bytesize)
      end

      uri = URI.parse(path)
      host_options = {}

      if uri.host
        host_options[:host]   = uri.host
        host_options[:port]   = uri.port
        host_options[:scheme] = uri.scheme
        path                  = uri.request_uri
      else
        host_options[:host] = host if host
        host_options[:port] = port if port
      end

      request_options = {
          method: http_method,
          expects: Array(expects),
          path: path_with_prefix(path),
          headers: request_headers,
          body: body_content,
          query: query
      }.merge(host_options)

      request_options.merge!(response_block: response_block) if response_block

      # Store the response into client.last_response
      @last_response = http_client.request(request_options)

      parse_response(@last_response)
    rescue Excon::Error::Unauthorized
      if token
        debug { 'Server reports access token expired' }

        if retried || !token || !token['refresh_token']
          raise Kontena::Errors::StandardError.new(401, 'The access token has expired and needs to be refreshed')
        end

        retried = true
        retry if refresh_token
      end
      raise Kontena::Errors::StandardError.new(401, 'Unauthorized')
    rescue Excon::Error::HTTPStatus => error
      if error.response.headers['Content-Encoding'] == 'gzip'
        error.response.body = Zlib::GzipReader.new(StringIO.new(error.response.body)).read
      end

      debug { "Request #{error.request[:method].upcase} #{error.request[:path]}: #{error.response.status} #{error.response.reason_phrase}: #{error.response.body}" }

      handle_error_response(error.response)
    end
Perform a HTTP request. Will try to refresh the access token and retry if it's
 expired or if the server responds with HTTP 401.

 Automatically parses a JSON response into a hash.

 After the request has been performed, the response can be inspected using
 client.last_response.

 @param http_method [Symbol] :get, :post, etc
 @param path [String] if it starts with / then prefix won't be used.
 @param body [Hash, String] will be encoded using #encode_body
 @param query [Hash] url query parameters
 @param headers [Hash] extra headers for request.
 @param response_block [Proc] for streaming requests, must respond to #call
 @param expects [Array] raises unless response status code matches this list.
 @param auth [Boolean] use token authentication default = true
 @return [Hash, String] response parsed response object