github.com/bndr/gojenkins@v1.1.0/node.go (about)

     1  // Copyright 2015 Vadim Kravcenko
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License"): you may
     4  // not use this file except in compliance with the License. You may obtain
     5  // a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    11  // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    12  // License for the specific language governing permissions and limitations
    13  // under the License.
    14  
    15  package gojenkins
    16  
    17  import (
    18  	"context"
    19  	"errors"
    20  )
    21  
    22  // Nodes
    23  
    24  type Computers struct {
    25  	BusyExecutors  int             `json:"busyExecutors"`
    26  	Computers      []*NodeResponse `json:"computer"`
    27  	DisplayName    string          `json:"displayName"`
    28  	TotalExecutors int             `json:"totalExecutors"`
    29  }
    30  
    31  type Node struct {
    32  	Raw     *NodeResponse
    33  	Jenkins *Jenkins
    34  	Base    string
    35  }
    36  
    37  type NodeResponse struct {
    38  	Class       string        `json:"_class"`
    39  	Actions     []interface{} `json:"actions"`
    40  	DisplayName string        `json:"displayName"`
    41  	Executors   []struct {
    42  		CurrentExecutable struct {
    43  			Number    int    `json:"number"`
    44  			URL       string `json:"url"`
    45  			SubBuilds []struct {
    46  				Abort             bool        `json:"abort"`
    47  				Build             interface{} `json:"build"`
    48  				BuildNumber       int         `json:"buildNumber"`
    49  				Duration          string      `json:"duration"`
    50  				Icon              string      `json:"icon"`
    51  				JobName           string      `json:"jobName"`
    52  				ParentBuildNumber int         `json:"parentBuildNumber"`
    53  				ParentJobName     string      `json:"parentJobName"`
    54  				PhaseName         string      `json:"phaseName"`
    55  				Result            string      `json:"result"`
    56  				Retry             bool        `json:"retry"`
    57  				URL               string      `json:"url"`
    58  			} `json:"subBuilds"`
    59  		} `json:"currentExecutable"`
    60  	} `json:"executors"`
    61  	Icon                string   `json:"icon"`
    62  	IconClassName       string   `json:"iconClassName"`
    63  	Idle                bool     `json:"idle"`
    64  	JnlpAgent           bool     `json:"jnlpAgent"`
    65  	LaunchSupported     bool     `json:"launchSupported"`
    66  	LoadStatistics      struct{} `json:"loadStatistics"`
    67  	ManualLaunchAllowed bool     `json:"manualLaunchAllowed"`
    68  	MonitorData         struct {
    69  		Hudson_NodeMonitors_ArchitectureMonitor interface{} `json:"hudson.node_monitors.ArchitectureMonitor"`
    70  		Hudson_NodeMonitors_ClockMonitor        interface{} `json:"hudson.node_monitors.ClockMonitor"`
    71  		Hudson_NodeMonitors_DiskSpaceMonitor    interface{} `json:"hudson.node_monitors.DiskSpaceMonitor"`
    72  		Hudson_NodeMonitors_ResponseTimeMonitor struct {
    73  			Average int64 `json:"average"`
    74  		} `json:"hudson.node_monitors.ResponseTimeMonitor"`
    75  		Hudson_NodeMonitors_SwapSpaceMonitor      interface{} `json:"hudson.node_monitors.SwapSpaceMonitor"`
    76  		Hudson_NodeMonitors_TemporarySpaceMonitor interface{} `json:"hudson.node_monitors.TemporarySpaceMonitor"`
    77  	} `json:"monitorData"`
    78  	NumExecutors       int64         `json:"numExecutors"`
    79  	Offline            bool          `json:"offline"`
    80  	OfflineCause       struct{}      `json:"offlineCause"`
    81  	OfflineCauseReason string        `json:"offlineCauseReason"`
    82  	OneOffExecutors    []interface{} `json:"oneOffExecutors"`
    83  	TemporarilyOffline bool          `json:"temporarilyOffline"`
    84  }
    85  
    86  func (n *Node) Info(ctx context.Context) (*NodeResponse, error) {
    87  	_, err := n.Poll(ctx)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  	return n.Raw, nil
    92  }
    93  
    94  func (n *Node) GetName() string {
    95  	return n.Raw.DisplayName
    96  }
    97  
    98  func (n *Node) Delete(ctx context.Context) (bool, error) {
    99  	resp, err := n.Jenkins.Requester.Post(ctx, n.Base+"/doDelete", nil, nil, nil)
   100  	if err != nil {
   101  		return false, err
   102  	}
   103  	return resp.StatusCode == 200, nil
   104  }
   105  
   106  func (n *Node) IsOnline(ctx context.Context) (bool, error) {
   107  	_, err := n.Poll(ctx)
   108  	if err != nil {
   109  		return false, err
   110  	}
   111  	return !n.Raw.Offline, nil
   112  }
   113  
   114  func (n *Node) IsTemporarilyOffline(ctx context.Context) (bool, error) {
   115  	_, err := n.Poll(ctx)
   116  	if err != nil {
   117  		return false, err
   118  	}
   119  	return n.Raw.TemporarilyOffline, nil
   120  }
   121  
   122  func (n *Node) IsIdle(ctx context.Context) (bool, error) {
   123  	_, err := n.Poll(ctx)
   124  	if err != nil {
   125  		return false, err
   126  	}
   127  	return n.Raw.Idle, nil
   128  }
   129  
   130  func (n *Node) IsJnlpAgent(ctx context.Context) (bool, error) {
   131  	_, err := n.Poll(ctx)
   132  	if err != nil {
   133  		return false, err
   134  	}
   135  	return n.Raw.JnlpAgent, nil
   136  }
   137  
   138  func (n *Node) SetOnline(ctx context.Context) (bool, error) {
   139  	_, err := n.Poll(ctx)
   140  
   141  	if err != nil {
   142  		return false, err
   143  	}
   144  
   145  	if n.Raw.Offline && !n.Raw.TemporarilyOffline {
   146  		return false, errors.New("Node is Permanently offline, can't bring it up")
   147  	}
   148  
   149  	if n.Raw.Offline && n.Raw.TemporarilyOffline {
   150  		return n.ToggleTemporarilyOffline(ctx)
   151  	}
   152  
   153  	return true, nil
   154  }
   155  
   156  func (n *Node) SetOffline(ctx context.Context, options ...interface{}) (bool, error) {
   157  	if !n.Raw.Offline {
   158  		return n.ToggleTemporarilyOffline(ctx, options...)
   159  	}
   160  	return false, errors.New("Node already Offline")
   161  }
   162  
   163  func (n *Node) ToggleTemporarilyOffline(ctx context.Context, options ...interface{}) (bool, error) {
   164  	state_before, err := n.IsTemporarilyOffline(ctx)
   165  	if err != nil {
   166  		return false, err
   167  	}
   168  	qr := map[string]string{"offlineMessage": "requested from gojenkins"}
   169  	if len(options) > 0 {
   170  		qr["offlineMessage"] = options[0].(string)
   171  	}
   172  	_, err = n.Jenkins.Requester.Post(ctx, n.Base+"/toggleOffline", nil, nil, qr)
   173  	if err != nil {
   174  		return false, err
   175  	}
   176  	new_state, err := n.IsTemporarilyOffline(ctx)
   177  	if err != nil {
   178  		return false, err
   179  	}
   180  	if state_before == new_state {
   181  		return false, errors.New("Node state not changed")
   182  	}
   183  	return true, nil
   184  }
   185  
   186  func (n *Node) Poll(ctx context.Context) (int, error) {
   187  	response, err := n.Jenkins.Requester.GetJSON(ctx, n.Base, n.Raw, nil)
   188  	if err != nil {
   189  		return 0, err
   190  	}
   191  	return response.StatusCode, nil
   192  }
   193  
   194  func (n *Node) LaunchNodeBySSH(ctx context.Context) (int, error) {
   195  	qr := map[string]string{
   196  		"json":   "",
   197  		"Submit": "Launch slave agent",
   198  	}
   199  	response, err := n.Jenkins.Requester.Post(ctx, n.Base+"/launchSlaveAgent", nil, nil, qr)
   200  	if err != nil {
   201  		return 0, err
   202  	}
   203  	return response.StatusCode, nil
   204  }
   205  
   206  func (n *Node) Disconnect(ctx context.Context) (int, error) {
   207  	qr := map[string]string{
   208  		"offlineMessage": "",
   209  		"json":           makeJson(map[string]string{"offlineMessage": ""}),
   210  		"Submit":         "Yes",
   211  	}
   212  	response, err := n.Jenkins.Requester.Post(ctx, n.Base+"/doDisconnect", nil, nil, qr)
   213  	if err != nil {
   214  		return 0, err
   215  	}
   216  	return response.StatusCode, nil
   217  }
   218  
   219  func (n *Node) GetLogText(ctx context.Context) (string, error) {
   220  	var log string
   221  
   222  	_, err := n.Jenkins.Requester.Post(ctx, n.Base+"/log", nil, nil, nil)
   223  	if err != nil {
   224  		return "", err
   225  	}
   226  
   227  	qr := map[string]string{"start": "0"}
   228  	_, err = n.Jenkins.Requester.GetJSON(ctx, n.Base+"/logText/progressiveHtml/", &log, qr)
   229  	if err != nil {
   230  		return "", nil
   231  	}
   232  
   233  	return log, nil
   234  }