resque-telework 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +6 -0
- data/MIT-LICENSE +20 -0
- data/README.md +151 -0
- data/doc/screenshots/view_overview.png +0 -0
- data/lib/resque-telework/global.rb +10 -0
- data/lib/resque-telework/manager.rb +205 -0
- data/lib/resque-telework/railtie.rb +11 -0
- data/lib/resque-telework/redis.rb +354 -0
- data/lib/resque-telework/server/views/misc.erb +21 -0
- data/lib/resque-telework/server/views/revision.erb +25 -0
- data/lib/resque-telework/server/views/stopit.erb +35 -0
- data/lib/resque-telework/server/views/telework.erb +262 -0
- data/lib/resque-telework/server/views/worker.erb +38 -0
- data/lib/resque-telework/server.rb +220 -0
- data/lib/resque-telework.rb +10 -0
- data/lib/tasks/telework.rake +98 -0
- data/resque-telework.gemspec +26 -0
- metadata +93 -0
| @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            <% @subtabs= my_substabs %>
         | 
| 2 | 
            +
            <h1>Miscellaneous Stuff</h1>
         | 
| 3 | 
            +
             | 
| 4 | 
            +
             | 
| 5 | 
            +
            Telework is a plugin for Resque
         | 
| 6 | 
            +
            <br><br>
         | 
| 7 | 
            +
            Please refer to <a href="https://github.com/gip/resque-telework">https://github.com/gip/resque-telework</a> for further information
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            <br><br>
         | 
| 10 | 
            +
            <table>
         | 
| 11 | 
            +
            <tr><th width="100">Telework version</th><td width="500"><%= Resque::Plugins::Telework::Version %></td></tr>
         | 
| 12 | 
            +
            <tr><th width="100">Redis interface version</th><td width="500"><%= Resque::Plugins::Telework::RedisInterfaceVersion %></td></tr>
         | 
| 13 | 
            +
            <tr><th width="100">Number of keys in Redis</th><td width="500"><%= redis.nb_keys %></td></tr>
         | 
| 14 | 
            +
            <tr><th width="100">Redis key prefix</th><td width="500"><%= redis.key_prefix %></td></tr>
         | 
| 15 | 
            +
            <tr><th width="100">Number of running workers</th><td width="500"><%= c=0; redis.hosts.each { |h| c+= redis.workers(h).length }; c %></td></tr>
         | 
| 16 | 
            +
            </table>
         | 
| 17 | 
            +
            <br><br>
         | 
| 18 | 
            +
            <h1>Configuration</h1><br>
         | 
| 19 | 
            +
            <table>
         | 
| 20 | 
            +
            <tr><th width="100">Configuration</th><td width="500"><%= redis.configuration %></td></tr>
         | 
| 21 | 
            +
            </table>
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            <h1>Revision <%= @revision%></h1>
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            <% res= {}
         | 
| 4 | 
            +
               redis.hosts.each do |h|
         | 
| 5 | 
            +
                 redis.revisions(h).each do |r|
         | 
| 6 | 
            +
            	   res[h]= r if r['revision']==@revision
         | 
| 7 | 
            +
            	 end
         | 
| 8 | 
            +
               end
         | 
| 9 | 
            +
            %>
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            <% if res.empty? %>
         | 
| 12 | 
            +
            <br>This revision is unknown
         | 
| 13 | 
            +
            <% else %>
         | 
| 14 | 
            +
            <br>
         | 
| 15 | 
            +
            <table>
         | 
| 16 | 
            +
            <tr><th width="100">Revision</th><td width="100"><%= res[res.keys[0]]['revision'] %></td></tr>
         | 
| 17 | 
            +
            <tr><th>Revision (short)</th><td><%= res[res.keys[0]]['revision_small'] %></td></tr>
         | 
| 18 | 
            +
            <tr><th width="100">Revision date</th><td width="100"><%= redis.fmt_date(res[res.keys[0]]['revision_date']) %></td></tr>
         | 
| 19 | 
            +
            <tr><th>Link</th><td><% l=res[res.keys[0]]['revision_link']%>  <a href="<%= l%>"><%= l %></a></td></tr>
         | 
| 20 | 
            +
            <tr><th>Deployed on</th><td><%= res.keys * ", " %></a></td></tr>
         | 
| 21 | 
            +
            <tr><th>Commit log</th><td><%=  redis.text_to_html(res[res.keys[0]]['revision_info'])%></a></td></tr>
         | 
| 22 | 
            +
            </table>
         | 
| 23 | 
            +
             | 
| 24 | 
            +
               
         | 
| 25 | 
            +
            <% end %>
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            <% object= @daemon ? "#{@host} daemon" :  "worker #{@worker}" %>
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            <% if @kill %>
         | 
| 4 | 
            +
            <h1>Killing <%= object %></h1>
         | 
| 5 | 
            +
            <% else %>
         | 
| 6 | 
            +
            <h1>Stopping <%= object %></h1>
         | 
| 7 | 
            +
            <% end %>
         | 
| 8 | 
            +
            <br>
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            <% if @host %>
         | 
| 11 | 
            +
            A command to <%= @kill ? "kill" : "stop" %> <%= object %> has been send to host <%= @host%>
         | 
| 12 | 
            +
            <% else %>
         | 
| 13 | 
            +
            Worker not found
         | 
| 14 | 
            +
            <% end %>
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            <% if @host %>
         | 
| 17 | 
            +
              <% unless @kill %>
         | 
| 18 | 
            +
            <br><br><% id= @worker %>
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            If that doesn't work, you may just kill it<br>
         | 
| 21 | 
            +
            <% unless @daemon %>
         | 
| 22 | 
            +
            <form id="kill<%=id%>" name="kill<%=id%>" method="post" action="/resque/telework_killit/<%=id%>" ><input type="submit" value= <%="\"Kill #{id}\"" %> >
         | 
| 23 | 
            +
            </form>
         | 
| 24 | 
            +
            <% else %>
         | 
| 25 | 
            +
            <form id="kill" name="kill" method="post" action="/resque/telework_killitd/<%=@host%>" ><input type="submit" value= <%="\"Kill\"" %> >
         | 
| 26 | 
            +
            </form>
         | 
| 27 | 
            +
            <% end %>
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              <% end %>
         | 
| 30 | 
            +
            <% end %>
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            <br><br>
         | 
| 33 | 
            +
            <a href="/resque/telework">Return to main Telework page</a>
         | 
| 34 | 
            +
             | 
| 35 | 
            +
             | 
| @@ -0,0 +1,262 @@ | |
| 1 | 
            +
            <% @subtabs= my_substabs %>
         | 
| 2 | 
            +
            <% if @refresh %>
         | 
| 3 | 
            +
            <META HTTP-EQUIV="refresh" CONTENT="<%= @refresh%>">
         | 
| 4 | 
            +
            <% end %>
         | 
| 5 | 
            +
             | 
| 6 | 
            +
             | 
| 7 | 
            +
            <script language="javascript" type="text/javascript">
         | 
| 8 | 
            +
            function hostlist(index) {
         | 
| 9 | 
            +
              document.startform.rev_filter.options.length = 0;
         | 
| 10 | 
            +
              switch(index) {
         | 
| 11 | 
            +
            	<% for host in redis.hosts %>
         | 
| 12 | 
            +
            	  <%= "case'#{host}':" %>
         | 
| 13 | 
            +
            	  <% i= 0 %>
         | 
| 14 | 
            +
            	  <% for rev in redis.revisions(host) %>
         | 
| 15 | 
            +
            	    <%= "document.startform.rev_filter.options[#{i}]= new Option('#{rev['revision_small']} from #{redis.fmt_date(rev['revision_date'])}', '#{rev['revision']} #{rev['revision_small']}' );" %>
         | 
| 16 | 
            +
            	  <% i+= 1 %>
         | 
| 17 | 
            +
            	  <% end %> break;
         | 
| 18 | 
            +
            	<% end %>
         | 
| 19 | 
            +
              };
         | 
| 20 | 
            +
              return true;
         | 
| 21 | 
            +
            };
         | 
| 22 | 
            +
            function queuelist(index) {
         | 
| 23 | 
            +
            	if(index != "(other)") {
         | 
| 24 | 
            +
            		document.startform.queue_text.value= "";		
         | 
| 25 | 
            +
            	}
         | 
| 26 | 
            +
            	return true;
         | 
| 27 | 
            +
            };
         | 
| 28 | 
            +
            function queuetext(val) {
         | 
| 29 | 
            +
            	if(val!="") {
         | 
| 30 | 
            +
            		document.startform.queue_filter.selectedIndex= 0;
         | 
| 31 | 
            +
            	}
         | 
| 32 | 
            +
            };
         | 
| 33 | 
            +
            function action(val) {
         | 
| 34 | 
            +
            	var params = val.split(",");
         | 
| 35 | 
            +
                var url = "";
         | 
| 36 | 
            +
                switch(params[0]) {
         | 
| 37 | 
            +
            	  case "start":
         | 
| 38 | 
            +
            	    url = "/start?task="+params[1]+"&host="+params[2]+"&rev="+document.getElementById("rev_filter_"+params[1]).value;
         | 
| 39 | 
            +
            	    break;
         | 
| 40 | 
            +
            	  case "pause":
         | 
| 41 | 
            +
            	    url = "/pause?task="+params[1]+"&host="+params[2];
         | 
| 42 | 
            +
            	    break;
         | 
| 43 | 
            +
            	  case "cont":
         | 
| 44 | 
            +
            	    url = "/pause?cont=true&task="+params[1]+"&host="+params[2];
         | 
| 45 | 
            +
            	    break;
         | 
| 46 | 
            +
            	  case "stop":
         | 
| 47 | 
            +
            	    url = "/stop?kill=false&task="+params[1]+"&host="+params[2];
         | 
| 48 | 
            +
            	    break;
         | 
| 49 | 
            +
            	  case "kill":
         | 
| 50 | 
            +
            	    url = "/stop?kill=true&task="+params[1]+"&host="+params[2];
         | 
| 51 | 
            +
            	    break;
         | 
| 52 | 
            +
            	  case "delete":
         | 
| 53 | 
            +
            	    url = "/delete?task="+params[1]+"&host="+params[2];
         | 
| 54 | 
            +
            	    break;	
         | 
| 55 | 
            +
            	  default:
         | 
| 56 | 
            +
            	    return true;
         | 
| 57 | 
            +
            	}
         | 
| 58 | 
            +
            	var form = document.createElement("form");
         | 
| 59 | 
            +
                form.setAttribute("method", "post");
         | 
| 60 | 
            +
                form.setAttribute("action", "/resque/telework"+url);
         | 
| 61 | 
            +
                document.body.appendChild(form);
         | 
| 62 | 
            +
                form.submit();
         | 
| 63 | 
            +
            };
         | 
| 64 | 
            +
            $(document).ready(function() {
         | 
| 65 | 
            +
            	document.startform.queue_filter.selectedIndex= 1;
         | 
| 66 | 
            +
            	hostlist($('#host_filter').val());
         | 
| 67 | 
            +
            	queuelist($('#queue_filter').val());
         | 
| 68 | 
            +
            });
         | 
| 69 | 
            +
            </script>
         | 
| 70 | 
            +
             | 
| 71 | 
            +
            <% redis.reconcile %>
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            <% notes= redis.notes_pop %>
         | 
| 74 | 
            +
            <% if notes.length>0 %>
         | 
| 75 | 
            +
             | 
| 76 | 
            +
            <h1>Notes</h1>
         | 
| 77 | 
            +
            <table>
         | 
| 78 | 
            +
            	<tr>
         | 
| 79 | 
            +
            		<th>User</th>
         | 
| 80 | 
            +
            		<th>Date</th>
         | 
| 81 | 
            +
            		<th>Note</th>
         | 
| 82 | 
            +
                    <th>Action</th>
         | 
| 83 | 
            +
            	</tr>
         | 
| 84 | 
            +
                <% for note,id in notes.each_with_index %>
         | 
| 85 | 
            +
                <tr>
         | 
| 86 | 
            +
            	    <td><%= note['user'] %></td>
         | 
| 87 | 
            +
            	    <td><%= "#{redis.fmt_date(note['date'], true)}" %></td>
         | 
| 88 | 
            +
            	    <td><%= note['note'] %></td>
         | 
| 89 | 
            +
                    <td>
         | 
| 90 | 
            +
                       <form id="deln" name="deln" method="post" action="/resque/telework_del_note/<%= id %>" ><input type="submit" value= "Delete" /></form>
         | 
| 91 | 
            +
                    </td>
         | 
| 92 | 
            +
            	</tr>
         | 
| 93 | 
            +
                <% end %>
         | 
| 94 | 
            +
            </table>
         | 
| 95 | 
            +
            <br>
         | 
| 96 | 
            +
            <% end %>
         | 
| 97 | 
            +
             | 
| 98 | 
            +
            <% if @scheduling %>
         | 
| 99 | 
            +
             | 
| 100 | 
            +
            <h1>Starting Workers</h1>
         | 
| 101 | 
            +
            <br>
         | 
| 102 | 
            +
             | 
| 103 | 
            +
            <div class="clearfix">
         | 
| 104 | 
            +
              <div class="control_panel sub_header">
         | 
| 105 | 
            +
                <form id="startform" name="startform" method="post" action="/resque/telework/start_task" >
         | 
| 106 | 
            +
                  <span class="host_filter">
         | 
| 107 | 
            +
                    Host: <%= generic_filter("host_filter", "h", redis.hosts, 
         | 
| 108 | 
            +
                                             "onchange=\"javascript: hostlist(this.options[this.selectedIndex].value);\"") %>
         | 
| 109 | 
            +
                  </span>
         | 
| 110 | 
            +
                  <span class="queue_filter">
         | 
| 111 | 
            +
                    Queue: <%= generic_filter("queue_filter", "q", ["(other)"] + Resque.redis.smembers('queues').sort << "*",
         | 
| 112 | 
            +
                                              "onchange=\"javascript: queuelist(this.options[this.selectedIndex].value);\"") %>
         | 
| 113 | 
            +
                    Queue: <input id="queue_text" type="text" name="qmanual" onkeyup="javascript: queuetext(this.value);" />
         | 
| 114 | 
            +
                  </span>
         | 
| 115 | 
            +
                  <span class="count_filter">
         | 
| 116 | 
            +
                    Count: <%= generic_filter("count_filter", "c", ['1', '2', '3', '4', '5', '6', '7', '8'] ) %>
         | 
| 117 | 
            +
                  </span>
         | 
| 118 | 
            +
                  <span class="rev_filter">
         | 
| 119 | 
            +
            	    Revision: <select id="rev_filter" name="r">
         | 
| 120 | 
            +
            		</select>
         | 
| 121 | 
            +
            	  </span>
         | 
| 122 | 
            +
            	  <span class="env_filter">
         | 
| 123 | 
            +
            	    Environment: <%= generic_filter("env_filter", "e", ['(default)', 'production', 'staging', 'development', 'test'] ) %>
         | 
| 124 | 
            +
            		</select>
         | 
| 125 | 
            +
            	  </span>
         | 
| 126 | 
            +
                  <input type="submit" value="Start" />
         | 
| 127 | 
            +
                </form>
         | 
| 128 | 
            +
              </div>
         | 
| 129 | 
            +
            </div><br><br><br><br>
         | 
| 130 | 
            +
            <% end %>
         | 
| 131 | 
            +
             | 
| 132 | 
            +
            <br>
         | 
| 133 | 
            +
            <% if @scheduling %>
         | 
| 134 | 
            +
            <h1>Adding Notes</h1>
         | 
| 135 | 
            +
            <br>
         | 
| 136 | 
            +
            <div class="clearfix">
         | 
| 137 | 
            +
              <div class="control_panel sub_header">
         | 
| 138 | 
            +
               <form id="noting" name="noting" method="post" action="/resque/telework/add_note">
         | 
| 139 | 
            +
            	<span class="note_user">User<input id="note_user" type="text" name="note_user"/></span>
         | 
| 140 | 
            +
            	<span class="note_text">Note<input id="note_text" type="text" size="100" name="note_text"/></span>
         | 
| 141 | 
            +
            	<span class="note_submit"><input type="submit" value="Add"/></span>
         | 
| 142 | 
            +
               </form>
         | 
| 143 | 
            +
               </div></div>
         | 
| 144 | 
            +
            <br><br><br><br>
         | 
| 145 | 
            +
            <% end %>
         | 
| 146 | 
            +
             | 
| 147 | 
            +
            <h1>Hosts, Revisions, Tasks and Workers</h1>
         | 
| 148 | 
            +
            <table>
         | 
| 149 | 
            +
                <tr>
         | 
| 150 | 
            +
                  <th>Host</th>
         | 
| 151 | 
            +
                  <th>Daemon</th>
         | 
| 152 | 
            +
                  <th>Revisions</th>
         | 
| 153 | 
            +
                  <th>Tasks and Workers</th>
         | 
| 154 | 
            +
                </tr>
         | 
| 155 | 
            +
                <% for host, status, info in redis.daemons_state %>
         | 
| 156 | 
            +
                  <tr>
         | 
| 157 | 
            +
                  <td><center><%= host%>
         | 
| 158 | 
            +
            	      <% if 'Alive'==status && info['cpu_load_1mins'] %>
         | 
| 159 | 
            +
            	         <br><%= "(%.2f%% cpu)" % (100*info['cpu_load_1mins']) %></center>
         | 
| 160 | 
            +
            	      <% end %>
         | 
| 161 | 
            +
            	  </td>
         | 
| 162 | 
            +
                  <% if 'Alive'==status %>
         | 
| 163 | 
            +
                    <td> <table><tr><td><%= "Alive (v#{info['version']})" %></td></tr>
         | 
| 164 | 
            +
            	                <tr><td>
         | 
| 165 | 
            +
            	                	<form id="stopd" name="stopd" method="post" action="/resque/telework_stopitd/<%= host %>" ><input type="submit" value= <%="\"Stop\""%> /></form>
         | 
| 166 | 
            +
            	                </td></tr>
         | 
| 167 | 
            +
            	         </table>
         | 
| 168 | 
            +
                    </td>
         | 
| 169 | 
            +
                  <% else %>
         | 
| 170 | 
            +
                    <td><%= status%></td>
         | 
| 171 | 
            +
                  <% end %>
         | 
| 172 | 
            +
                  <td><%= redis.revisions(host).length %> revision(s) installed
         | 
| 173 | 
            +
                  <table><tr>
         | 
| 174 | 
            +
            	     <th>Revision</th>
         | 
| 175 | 
            +
            	     <th>Branch</th>
         | 
| 176 | 
            +
            	     <th>Deployed</th>
         | 
| 177 | 
            +
            	  </tr>
         | 
| 178 | 
            +
                  <% for rev in redis.revisions(host) %>
         | 
| 179 | 
            +
                  <tr>
         | 
| 180 | 
            +
            	     <td><a href= <%= "/resque/telework/revision/#{rev['revision']}" %> ><%= "#{rev['revision_small']}" %></a></td>
         | 
| 181 | 
            +
            	     <td><%= "#{rev['revision_branch']}" %></td>
         | 
| 182 | 
            +
            	     <td><%= "#{redis.fmt_date(rev['revision_deployement_date'], true)}" %></td>
         | 
| 183 | 
            +
                  </tr>
         | 
| 184 | 
            +
                  <%end%>
         | 
| 185 | 
            +
                   </table>
         | 
| 186 | 
            +
                  </td>
         | 
| 187 | 
            +
                  <td><%= redis.tasks(host).length%> task(s)
         | 
| 188 | 
            +
            	  <table><tr>
         | 
| 189 | 
            +
            		</tr><th>Task</th>
         | 
| 190 | 
            +
            		     <th>Status</th>
         | 
| 191 | 
            +
            		     <th>Queue(s)</th>
         | 
| 192 | 
            +
            		     <th>Count</th>
         | 
| 193 | 
            +
            		     <th>Revision</th>
         | 
| 194 | 
            +
            		     <th>Action</th>
         | 
| 195 | 
            +
            		     <th>Worker(s)</th>
         | 
| 196 | 
            +
            		<tr>
         | 
| 197 | 
            +
            	  <% for id, info in redis.tasks(host) %>
         | 
| 198 | 
            +
            	     <% status= info['worker_status'] %>
         | 
| 199 | 
            +
            	     <% status= 'Stopped' if status.blank? %>
         | 
| 200 | 
            +
            	     <% running= status!='Stopped' %>
         | 
| 201 | 
            +
            	     <% paused=  status=='Paused' %>
         | 
| 202 | 
            +
                         <td><%= "<a hreftbd=\"/resque/telework/task/#{host}/#{id}\">#{id}</a>" %>
         | 
| 203 | 
            +
            	    </td><td><%= "#{status}" %>
         | 
| 204 | 
            +
            	    </td><td><%= "#{info['queue'].gsub(/,/,'<br/>')}" %>
         | 
| 205 | 
            +
            	    </td><td><%= "#{info['worker_count']}" %>
         | 
| 206 | 
            +
            		</td><td><% if running %><a href= <%= "/resque/telework/revision/#{info['revision']}" %> ><%= "#{info['revision_small']}" %></a>
         | 
| 207 | 
            +
            			     <% else %> <select id= <%= "\"rev_filter_#{id}\"" %> name="r"/>
         | 
| 208 | 
            +
            			                   <% for rev in redis.revisions(host) %>
         | 
| 209 | 
            +
            			                   <option value=<%= "\"#{rev['revision']},#{rev['revision_small']}\"" %> ><%= rev['revision_small'] %></option>
         | 
| 210 | 
            +
            			                   <% end %>
         | 
| 211 | 
            +
            			                </select> 
         | 
| 212 | 
            +
            			     <% end %>
         | 
| 213 | 
            +
                    </td><td>
         | 
| 214 | 
            +
            	        <select id="action" name="a" onchange="javascript: action(this.options[this.selectedIndex].value);" >
         | 
| 215 | 
            +
            	        	<option select="selected" value="select">Select</option>
         | 
| 216 | 
            +
            	            <option <%= 'disabled="disabled"'     if running %> value=<%= "\"start,#{id},#{host}\"" %> >Start worker</option>
         | 
| 217 | 
            +
            	            <option <%= 'disabled="disabled"' unless running %> value=<%= "\"stop,#{id},#{host}\"" %> >Stop worker</option>
         | 
| 218 | 
            +
            	            <option <%= 'disabled="disabled"' unless running %> value=<%= "\"kill,#{id},#{host}\"" %> >Kill worker</option>
         | 
| 219 | 
            +
            	            <option <%= 'disabled="disabled"'     if (!running || paused) %> value=<%= "\"pause,#{id},#{host}\"" %> >Pause worker</option>
         | 
| 220 | 
            +
            	            <option <%= 'disabled="disabled"' unless paused %> value=<%= "\"cont,#{id},#{host}\"" %> >Resume worker</option>
         | 
| 221 | 
            +
            	            <option <%= 'disabled="disabled"'     if running %> value=<%= "\"delete,#{id},#{host}\"" %> >Delete</option>
         | 
| 222 | 
            +
            	        </select>
         | 
| 223 | 
            +
            	     </td><td align="center"><p align="center"><font size="1">
         | 
| 224 | 
            +
            		    <% info['worker_id'].zip(info['worker_pid']) do |id,pid| %>
         | 
| 225 | 
            +
            		      <%= "<a href=\"/resque/telework/worker/#{host}/#{id}\">Worker #{id}</a>" if running %><br/>
         | 
| 226 | 
            +
            	          <font size=1><% l= "#{host}:#{pid}" %><%= "<a href=\"/resque/workers/#{l}:#{info['queue']}\">#{l}</a>" if running %></font><br/>
         | 
| 227 | 
            +
            	        <% end %>
         | 
| 228 | 
            +
            	        </font></p>
         | 
| 229 | 
            +
            	   </td></tr>
         | 
| 230 | 
            +
            	  <%end%>
         | 
| 231 | 
            +
            	  </table>
         | 
| 232 | 
            +
            	  </td>
         | 
| 233 | 
            +
                  </tr>
         | 
| 234 | 
            +
                <% end %>
         | 
| 235 | 
            +
            </table>
         | 
| 236 | 
            +
             | 
| 237 | 
            +
            <br>
         | 
| 238 | 
            +
            <% if @status_messages %>
         | 
| 239 | 
            +
            <h1>Status Messages</h1>
         | 
| 240 | 
            +
            <table>
         | 
| 241 | 
            +
                <tr>
         | 
| 242 | 
            +
                  <th>Host</th>
         | 
| 243 | 
            +
                  <th>Severity</th>
         | 
| 244 | 
            +
                  <th>Date</th>
         | 
| 245 | 
            +
                  <th>Message</th>
         | 
| 246 | 
            +
                </tr>
         | 
| 247 | 
            +
                <% for info in redis.statuses(@status_messages) %>
         | 
| 248 | 
            +
                <% c= info['severity']=='Error' ? "bgcolor=\"#ff0000\"" : "" %>
         | 
| 249 | 
            +
                  <tr>
         | 
| 250 | 
            +
            	    <td <%= c %>><%= info['host'] %></td>
         | 
| 251 | 
            +
            	    <td <%= c %>><%= info['severity'] %></td>
         | 
| 252 | 
            +
            	    <td <%= c %>><%= redis.fmt_date(info['date']) %></td>
         | 
| 253 | 
            +
            	    <td <%= c %>><%= info['message'] %></td>
         | 
| 254 | 
            +
            	  </tr>
         | 
| 255 | 
            +
               <% end %>
         | 
| 256 | 
            +
            </table>
         | 
| 257 | 
            +
             | 
| 258 | 
            +
            <%end%>
         | 
| 259 | 
            +
             | 
| 260 | 
            +
             | 
| 261 | 
            +
             | 
| 262 | 
            +
            </div>
         | 
| @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            <h1>Worker <%= @worker%></h1>
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            <% worker= redis.workers_by_id(@host, @worker) %>
         | 
| 4 | 
            +
            <% if worker %>
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Running on host <%= @host %>
         | 
| 7 | 
            +
            <br><br>
         | 
| 8 | 
            +
            Link: <% l= "#{@host}:#{worker['pid']}" %><%= "<a href=\"/resque/workers/#{l}:#{worker['environment']['QUEUE']}\">#{l}</a>" %>
         | 
| 9 | 
            +
            <br><br>
         | 
| 10 | 
            +
            TODO: better formatting for table below!
         | 
| 11 | 
            +
            <table>
         | 
| 12 | 
            +
            	<% for k in worker.keys %>
         | 
| 13 | 
            +
            	<tr><th width="30"><%= k %></th><td width="600"><%= worker[k] %></td></tr>
         | 
| 14 | 
            +
            	<% end %>
         | 
| 15 | 
            +
            </table>
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            <br>
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            <h1>Logs</h1>
         | 
| 20 | 
            +
            <% log= redis.logs_by_id(@host, @worker) %>
         | 
| 21 | 
            +
            <br>
         | 
| 22 | 
            +
            <% if log %>
         | 
| 23 | 
            +
            <%= "Logs as of #{redis.fmt_date(log['date'])}"%>
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            <table>
         | 
| 26 | 
            +
            <tr><th width="30">STDERR</th><td width="600"><%= redis.text_to_html(log['log_stderr']) %></td></tr>
         | 
| 27 | 
            +
            <tr><th width="30">STDOUT</th><td width="600"><%= redis.text_to_html(log['log_stdout']) %></td></tr>
         | 
| 28 | 
            +
            </table>
         | 
| 29 | 
            +
             | 
| 30 | 
            +
             | 
| 31 | 
            +
            <% else %>
         | 
| 32 | 
            +
            Logs are not available
         | 
| 33 | 
            +
            <% end %>
         | 
| 34 | 
            +
             | 
| 35 | 
            +
             | 
| 36 | 
            +
            <% else %>
         | 
| 37 | 
            +
            Worker not found
         | 
| 38 | 
            +
            <% end %>
         | 
| @@ -0,0 +1,220 @@ | |
| 1 | 
            +
            module Resque
         | 
| 2 | 
            +
              module Plugins
         | 
| 3 | 
            +
                module Telework
         | 
| 4 | 
            +
                  module Server
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                    require 'erb'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                    VIEW_PATH = File.join(File.dirname(__FILE__), 'server', 'views')
         | 
| 9 | 
            +
                    PUBLIC_PATH = File.join(File.dirname(__FILE__), 'server', 'public')
         | 
| 10 | 
            +
                                    
         | 
| 11 | 
            +
                    def self.registered( app )
         | 
| 12 | 
            +
                      appn= 'Telework'
         | 
| 13 | 
            +
                      
         | 
| 14 | 
            +
                      # This helpers adds stuff to the app closure
         | 
| 15 | 
            +
                      app.helpers do
         | 
| 16 | 
            +
                        @@myredis= TeleworkRedis.new
         | 
| 17 | 
            +
                        def redis
         | 
| 18 | 
            +
                          @@myredis
         | 
| 19 | 
            +
                        end
         | 
| 20 | 
            +
                        def my_substabs
         | 
| 21 | 
            +
                          ["Overview", "Start", "Misc"]
         | 
| 22 | 
            +
                        end
         | 
| 23 | 
            +
                        def my_show(page, layout = true)
         | 
| 24 | 
            +
                          response["Cache-Control"] = "max-age=0, private, must-revalidate"
         | 
| 25 | 
            +
                          begin
         | 
| 26 | 
            +
                            erb(File.read(File.join(VIEW_PATH, "#{page}.erb")), {:layout => layout}, :resque => Resque)
         | 
| 27 | 
            +
                          rescue Errno::ECONNREFUSED
         | 
| 28 | 
            +
                            erb :error, {:layout => false}, :error => "Can't connect to Redis! (#{Resque.redis_id})"
         | 
| 29 | 
            +
                          end
         | 
| 30 | 
            +
                        end
         | 
| 31 | 
            +
                        def generic_filter(id, name, list, more= "")
         | 
| 32 | 
            +
                          html = "<select id=\"#{id}\" name=\"#{name}\" #{more}>"
         | 
| 33 | 
            +
                          #html += "<option value=\"\">-</option>"
         | 
| 34 | 
            +
                          value= list[0]
         | 
| 35 | 
            +
                          list.each do |k|
         | 
| 36 | 
            +
                            selected = k == value ? 'selected="selected"' : ''
         | 
| 37 | 
            +
                            html += "<option #{selected} value=\"#{k}\">#{k}</option>"
         | 
| 38 | 
            +
                          end
         | 
| 39 | 
            +
                          html += "</select>"
         | 
| 40 | 
            +
                        end
         | 
| 41 | 
            +
                        
         | 
| 42 | 
            +
                      end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                      app.get "/#{appn.downcase}" do
         | 
| 45 | 
            +
                        redirect "/resque/#{appn.downcase}/Overview"
         | 
| 46 | 
            +
                      end
         | 
| 47 | 
            +
                      
         | 
| 48 | 
            +
                      app.get "/#{appn.downcase}/Overview" do
         | 
| 49 | 
            +
                        @status_messages= 100
         | 
| 50 | 
            +
                        @refresh= 10
         | 
| 51 | 
            +
                        @scheduling= nil
         | 
| 52 | 
            +
                        my_show appn.downcase
         | 
| 53 | 
            +
                      end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                      app.get "/#{appn.downcase}/Start" do
         | 
| 56 | 
            +
                        @status_messages= 100
         | 
| 57 | 
            +
                        @scheduling= true
         | 
| 58 | 
            +
                        my_show appn.downcase
         | 
| 59 | 
            +
                      end
         | 
| 60 | 
            +
                      
         | 
| 61 | 
            +
                      app.get "/#{appn.downcase}/Misc" do
         | 
| 62 | 
            +
                        my_show 'misc'
         | 
| 63 | 
            +
                      end          
         | 
| 64 | 
            +
                      
         | 
| 65 | 
            +
                      app.get "/#{appn.downcase}/revision/:revision" do
         | 
| 66 | 
            +
                        @revision= params[:revision]
         | 
| 67 | 
            +
                        my_show 'revision' 
         | 
| 68 | 
            +
                      end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                      app.get "/#{appn.downcase}/worker/:host/:worker" do
         | 
| 71 | 
            +
                        @worker= params[:worker]
         | 
| 72 | 
            +
                        @host= params[:host]
         | 
| 73 | 
            +
                        my_show 'worker' 
         | 
| 74 | 
            +
                      end
         | 
| 75 | 
            +
                      
         | 
| 76 | 
            +
                      app.get "/#{appn.downcase}/config" do
         | 
| 77 | 
            +
                        content_type :json
         | 
| 78 | 
            +
                        redis.configuration
         | 
| 79 | 
            +
                      end
         | 
| 80 | 
            +
                      
         | 
| 81 | 
            +
                      app.post "/#{appn.downcase}_stopit/:worker" do
         | 
| 82 | 
            +
                        @worker= params[:worker]
         | 
| 83 | 
            +
                        @host= nil
         | 
| 84 | 
            +
                        @daemon= nil
         | 
| 85 | 
            +
                        redis.hosts.each do |h|
         | 
| 86 | 
            +
                          redis.workers(h).each do |id, info|
         | 
| 87 | 
            +
                            @host= h if id==@worker # TODO: break nested loops
         | 
| 88 | 
            +
                          end
         | 
| 89 | 
            +
                        end
         | 
| 90 | 
            +
                        redis.cmds_push( @host, { 'command' => 'stop_worker', 'worker_id'=> @worker } ) if @host
         | 
| 91 | 
            +
                        my_show 'stopit'
         | 
| 92 | 
            +
                      end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                      app.post "/#{appn.downcase}_stopitd/:host" do
         | 
| 95 | 
            +
                        # Todo - check that the host indeed exists
         | 
| 96 | 
            +
                        @host= params[:host]
         | 
| 97 | 
            +
                        @daemon= true
         | 
| 98 | 
            +
                        redis.cmds_push( @host, { 'command' => 'stop_daemon' } )
         | 
| 99 | 
            +
                        my_show 'stopit'
         | 
| 100 | 
            +
                      end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                      app.post "/#{appn.downcase}_killitd/:host" do
         | 
| 103 | 
            +
                        # Todo - check that the host indeed exists
         | 
| 104 | 
            +
                        @host= params[:host]
         | 
| 105 | 
            +
                        @daemon= true
         | 
| 106 | 
            +
                        @kill= true
         | 
| 107 | 
            +
                        redis.cmds_push( @host, { 'command' => 'kill_daemon' } )
         | 
| 108 | 
            +
                        my_show 'stopit'
         | 
| 109 | 
            +
                      end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                      app.post "/#{appn.downcase}_killit/:worker" do
         | 
| 112 | 
            +
                        @worker= params[:worker]
         | 
| 113 | 
            +
                        @host= nil
         | 
| 114 | 
            +
                        @kill= true
         | 
| 115 | 
            +
                        redis.hosts.each do |h|
         | 
| 116 | 
            +
                          redis.workers(h).each do |id, info|
         | 
| 117 | 
            +
                            @host= h if id==@worker # TODO: break nested loops
         | 
| 118 | 
            +
                          end
         | 
| 119 | 
            +
                        end
         | 
| 120 | 
            +
                        redis.cmds_push( @host, { 'command' => 'kill_worker', 'worker_id'=> @worker } ) if @host
         | 
| 121 | 
            +
                        my_show 'stopit'
         | 
| 122 | 
            +
                      end
         | 
| 123 | 
            +
                      
         | 
| 124 | 
            +
                      app.post "/#{appn.downcase}/add_note" do
         | 
| 125 | 
            +
                        @user= params[:note_user]
         | 
| 126 | 
            +
                        @date= Time.now
         | 
| 127 | 
            +
                        @note= params[:note_text]
         | 
| 128 | 
            +
                        redis.notes_push({ 'user'=> @user, 'date'=> @date, 'note' => @note })
         | 
| 129 | 
            +
                        redirect "/resque/#{appn.downcase}"
         | 
| 130 | 
            +
                      end
         | 
| 131 | 
            +
                      
         | 
| 132 | 
            +
                      app.post "/#{appn.downcase}_del_note/:note" do
         | 
| 133 | 
            +
                        @note_id= params[:note]
         | 
| 134 | 
            +
                        redis.notes_del(@note_id)
         | 
| 135 | 
            +
                        redirect "/resque/#{appn.downcase}"
         | 
| 136 | 
            +
                      end
         | 
| 137 | 
            +
                      
         | 
| 138 | 
            +
                      # Start a task
         | 
| 139 | 
            +
                      app.post "/telework/start_task" do
         | 
| 140 | 
            +
                        @host= params[:h]
         | 
| 141 | 
            +
                        @queue= params[:q]
         | 
| 142 | 
            +
                        @qmanual= params[:qmanual]
         | 
| 143 | 
            +
                        @count= params[:c]
         | 
| 144 | 
            +
                        @rev= params[:r].split(' ')
         | 
| 145 | 
            +
                        @env= params[:e]
         | 
| 146 | 
            +
                        @q= @qmanual.blank? ? @queue : @qmanual
         | 
| 147 | 
            +
                        id= redis.unique_id.to_s
         | 
| 148 | 
            +
                        redis.tasks_add( @host , id, { 'revision' => @rev[0], 'revision_small' => @rev[1],
         | 
| 149 | 
            +
                                                       'task_id' => id, 'worker_count' => @count,
         | 
| 150 | 
            +
                                                       'rails_env' => @env, 'queue' => @q,
         | 
| 151 | 
            +
                                                       'exec' => "bundle exec rake resque:work --trace",
         | 
| 152 | 
            +
                                                       'worker_id' => [], 'worker_status' => 'Stopped',
         | 
| 153 | 
            +
                                                       'log_snapshot_period' => 30,
         | 
| 154 | 
            +
                                                       'log_snapshot_lines' => 40 } )
         | 
| 155 | 
            +
                        redirect "/resque/#{appn.downcase}"          
         | 
| 156 | 
            +
                      end
         | 
| 157 | 
            +
                      
         | 
| 158 | 
            +
                      app.post "/#{appn.downcase}/delete" do
         | 
| 159 | 
            +
                        @task_id= params[:task]
         | 
| 160 | 
            +
                        @host= params[:host]
         | 
| 161 | 
            +
                        redis.tasks_rem( @host, @task_id )
         | 
| 162 | 
            +
                        redirect "/resque/#{appn.downcase}"            
         | 
| 163 | 
            +
                      end
         | 
| 164 | 
            +
                      
         | 
| 165 | 
            +
                      # Start workers
         | 
| 166 | 
            +
                      app.post "/#{appn.downcase}/start" do
         | 
| 167 | 
            +
                        @task_id= params[:task]
         | 
| 168 | 
            +
                        @host= params[:host]
         | 
| 169 | 
            +
                        @rev= params[:rev].split(',')
         | 
| 170 | 
            +
                        @task= redis.tasks_by_id(@host, @task_id)
         | 
| 171 | 
            +
                        count= @task['worker_count'] || 1
         | 
| 172 | 
            +
                        id= []
         | 
| 173 | 
            +
                        for i in 1..count.to_i do
         | 
| 174 | 
            +
                          w= @task
         | 
| 175 | 
            +
                          w['worker_id']= redis.unique_id.to_s
         | 
| 176 | 
            +
                          id << w['worker_id']
         | 
| 177 | 
            +
                          w['worker_status']= 'Starting'
         | 
| 178 | 
            +
                          w['revision']= @rev[0]
         | 
| 179 | 
            +
                          w['revision_small']= @rev[1]
         | 
| 180 | 
            +
                          w['command']= 'start_worker'
         | 
| 181 | 
            +
                          w['task_id']= @task_id
         | 
| 182 | 
            +
                          redis.cmds_push( @host, w )
         | 
| 183 | 
            +
                        end
         | 
| 184 | 
            +
                        @task['worker_id']= id
         | 
| 185 | 
            +
                        redis.tasks_add( @host, @task_id, @task )
         | 
| 186 | 
            +
                        redirect "/resque/#{appn.downcase}"
         | 
| 187 | 
            +
                      end
         | 
| 188 | 
            +
             | 
| 189 | 
            +
                      app.post "/#{appn.downcase}/pause" do
         | 
| 190 | 
            +
                        @task_id= params[:task]
         | 
| 191 | 
            +
                        @host= params[:host]
         | 
| 192 | 
            +
                        @cont= params[:cont]=="true"
         | 
| 193 | 
            +
                        @task= redis.tasks_by_id(@host, @task_id)
         | 
| 194 | 
            +
                        @task['worker_id'].each do |id|
         | 
| 195 | 
            +
                          redis.cmds_push( @host, { 'command' => 'signal_worker', 'worker_id'=> id, 'action' => @cont ? 'CONT' : 'PAUSE' } ) 
         | 
| 196 | 
            +
                        end
         | 
| 197 | 
            +
                        redirect "/resque/#{appn.downcase}"
         | 
| 198 | 
            +
                      end
         | 
| 199 | 
            +
             | 
| 200 | 
            +
                      app.post "/#{appn.downcase}/stop" do
         | 
| 201 | 
            +
                        @task_id= params[:task]
         | 
| 202 | 
            +
                        @host= params[:host]
         | 
| 203 | 
            +
                        @kill= params[:kill]=="true"
         | 
| 204 | 
            +
                        @task= redis.tasks_by_id(@host, @task_id)
         | 
| 205 | 
            +
                        @task['worker_id'].each do |id|
         | 
| 206 | 
            +
                          redis.cmds_push( @host, { 'command' => 'signal_worker', 'worker_id'=> id, 'action' => @kill ? 'KILL' : 'QUIT' } ) 
         | 
| 207 | 
            +
                        end
         | 
| 208 | 
            +
                        redirect "/resque/#{appn.downcase}"
         | 
| 209 | 
            +
                      end
         | 
| 210 | 
            +
                                          
         | 
| 211 | 
            +
                      app.tabs << appn
         | 
| 212 | 
            +
                      
         | 
| 213 | 
            +
                    end
         | 
| 214 | 
            +
                  
         | 
| 215 | 
            +
                  end
         | 
| 216 | 
            +
                end
         | 
| 217 | 
            +
              end
         | 
| 218 | 
            +
            end
         | 
| 219 | 
            +
             | 
| 220 | 
            +
            Resque::Server.register Resque::Plugins::Telework::Server
         |