From owner-p4-projects@FreeBSD.ORG Mon Aug 20 00:57:15 2007 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id A95F316A469; Mon, 20 Aug 2007 00:57:15 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 25AFC16A417 for ; Mon, 20 Aug 2007 00:57:15 +0000 (UTC) (envelope-from andrew@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 14BEC13C48D for ; Mon, 20 Aug 2007 00:57:15 +0000 (UTC) (envelope-from andrew@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id l7K0vFOv028700 for ; Mon, 20 Aug 2007 00:57:15 GMT (envelope-from andrew@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id l7K0vEVP028697 for perforce@freebsd.org; Mon, 20 Aug 2007 00:57:14 GMT (envelope-from andrew@freebsd.org) Date: Mon, 20 Aug 2007 00:57:14 GMT Message-Id: <200708200057.l7K0vEVP028697@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to andrew@freebsd.org using -f From: Andrew Turner To: Perforce Change Reviews Cc: Subject: PERFORCE change 125368 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 20 Aug 2007 00:57:16 -0000 http://perforce.freebsd.org/chv.cgi?CH=125368 Change 125368 by andrew@andrew_hermies on 2007/08/20 00:56:57 Add the get_services call to list the services avaliable to restart Impement the restart_services call to restart services Add a button to send the restart_services call to the backend Add a services item to the computer view. When selected it will send a get_services and display the services returned on the ypdates area Add the getType() method to facund objects Spell True correctly for Python Affected files ... .. //depot/projects/soc2007/andrew-update/backend/facund-be.c#25 edit .. //depot/projects/soc2007/andrew-update/frontend/facund-fe.glade#6 edit .. //depot/projects/soc2007/andrew-update/frontend/facund/computer.py#14 edit .. //depot/projects/soc2007/andrew-update/frontend/facund/controller.py#7 edit .. //depot/projects/soc2007/andrew-update/frontend/facund/data.py#4 edit .. //depot/projects/soc2007/andrew-update/frontend/facund/gui/main_window.py#12 edit .. //depot/projects/soc2007/andrew-update/frontend/facund/gui/update_model.py#3 edit .. //depot/projects/soc2007/andrew-update/frontend/facund/network/__init__.py#14 edit Differences ... ==== //depot/projects/soc2007/andrew-update/backend/facund-be.c#25 (text+ko) ==== @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -85,6 +86,8 @@ struct facund_object *); static struct facund_response *facund_call_rollback_patches(const char *, struct facund_object *); +static struct facund_response *facund_call_get_services(const char *, + struct facund_object *obj); static struct facund_response *facund_call_restart_services(const char *, struct facund_object *); @@ -1093,10 +1096,158 @@ } static struct facund_response * -facund_call_restart_services(const char *id __unused, struct facund_object *obj __unused) +facund_call_get_services(const char *id __unused, struct facund_object *obj __unused) +{ + struct facund_object *dirs, *cur_dir; + const char *base_dir; + struct dirent *de; + unsigned int pos; + DIR *d; + + if (obj == NULL) { + /* TODO: Don't use magic numbers */ + return facund_response_new(id, 1, "No data sent", NULL); + } + + /* Read in the base dir to get the services for */ + base_dir = NULL; + if (facund_object_get_type(obj) != FACUND_STRING) { + return facund_response_new(id, 1, "Incorrect data", NULL); + } + base_dir = facund_object_get_string(obj); + if (base_dir == NULL) { + return facund_response_new(id, 1, "Malloc failed", NULL); + } + if (strcmp(base_dir, "/") != 0) { + return facund_response_new(id, 1, + "Can only restart services in /", NULL); + } + for (pos = 0; pos < watched_db_count; pos++) { + if (strcmp(watched_db[pos].db_base, base_dir) == 0) { + break; + } + } + if (pos == watched_db_count) { + return facund_response_new(id, 1, "Unknown base dir", NULL); + } + + d = opendir("/etc/rc.d/"); + if (d == NULL) { + return facund_response_new(id, 1, "Could not open /etc/rc.d/", + NULL); + } + + dirs = facund_object_new_array(); + while ((de = readdir(d)) != NULL) { + /* Don't look at hidden files */ + if (de->d_name[0] == '.') + continue; + + cur_dir = facund_object_new_string(); + facund_object_set_string(cur_dir, de->d_name); + facund_object_array_append(dirs, cur_dir); + } + if (facund_object_array_size(dirs) == 0) { + facund_object_free(dirs); + return facund_response_new(id, 1, "No services found", NULL); + } + + return facund_response_new(id, 0, "Services found", dirs); +} + +static struct facund_response * +facund_call_restart_services(const char *id, struct facund_object *obj) { - fprintf(stderr, "STUB: %s\n", __func__); - return NULL; + const char *base_dir, *service; + const struct facund_object *cur; + char service_script[PATH_MAX], *cmd; + unsigned int pos; + struct stat sb; + + if (obj == NULL) { + /* TODO: Don't use magic numbers */ + return facund_response_new(id, 1, "No data sent", NULL); + } + + base_dir = NULL; + service = NULL; + + if (facund_object_get_type(obj) != FACUND_ARRAY) { + return facund_response_new(id, 1, "Incorrect data", NULL); + } + if (facund_object_array_size(obj) != 2) { + return facund_response_new(id, 1, "Incorrect data", NULL); + } + + /* Find the base dir */ + cur = facund_object_get_array_item(obj, 0); + if (facund_object_get_type(cur) != FACUND_STRING) { + return facund_response_new(id, 1, "Incorrect data", NULL); + } + base_dir = facund_object_get_string(cur); + if (base_dir == NULL) { + return facund_response_new(id, 1, "Malloc failed", NULL); + } + /* + * We can only restart a service if the base dir + * is / as we don't know how to signal any other's. + * eg. if it is in a jail we will have to use jexec + * but we don't know if this base is in a jail + */ + if (strcmp(base_dir, "/") != 0) { + return facund_response_new(id, 1, + "Can only restart services in /", NULL); + } + for (pos = 0; pos < watched_db_count; pos++) { + if (strcmp(watched_db[pos].db_base, base_dir) == 0) { + break; + } + } + if (pos == watched_db_count) { + return facund_response_new(id, 1, "Unknown base dir", NULL); + } + + /* Find the service to restart */ + cur = facund_object_get_array_item(obj, 1); + if (facund_object_get_type(cur) != FACUND_STRING) { + return facund_response_new(id, 1, "Incorrect data", NULL); + } + service = facund_object_get_string(cur); + if (service == NULL) { + return facund_response_new(id, 1, "Malloc failed", NULL); + } + do { + /* Try services in /etc/rc.d */ + snprintf(service_script, PATH_MAX, "/etc/rc.d/%s", service); + if (stat(service_script, &sb) == 0) { + break; + } + + /* Try services in /usr/local/etc/rc.d */ + snprintf(service_script, PATH_MAX, "/usr/local/etc/rc.d/%s", + service); + if (stat(service_script, &sb) == 0) { + break; + } + + return facund_response_new(id, 1, "Unknown service", NULL); + } while (0); + + /* Attempt to restart the service */ + asprintf(&cmd, "%s restart", service_script); + if (cmd == NULL) { + return facund_response_new(id, 1, "Malloc failed", NULL); + } + seteuid(0); + if (system(cmd) != 0) { + free(cmd); + seteuid(getuid()); + return facund_response_new(id, 1, "Service restart failed", + NULL); + } + free(cmd); + seteuid(getuid()); + return facund_response_new(id, 0, "Service restart successful", NULL); } static void @@ -1203,6 +1354,7 @@ facund_server_add_call("list_installed", facund_call_list_installed); facund_server_add_call("install_patches", facund_call_install_patches); facund_server_add_call("rollback_patches",facund_call_rollback_patches); + facund_server_add_call("get_services", facund_call_get_services); facund_server_add_call("restart_services",facund_call_restart_services); pthread_create(&update_thread, NULL, look_for_updates, NULL); ==== //depot/projects/soc2007/andrew-update/frontend/facund-fe.glade#6 (text+ko) ==== @@ -1,6 +1,6 @@ - + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK @@ -105,32 +105,39 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 2 + 3 2 5 5 - + True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Connect + Restart 0 + + 2 + 2 + 3 + - + True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Disconnect + Remove 0 1 2 + 1 + 2 @@ -148,21 +155,29 @@ - + True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Remove + Disconnect 0 1 2 - 1 - 2 + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Connect + 0 + + False @@ -261,34 +276,27 @@ 3 10 - + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Computer's description -This is a Human redable -name for the computer + Socket location +Leave blank for +the default socket - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - 1 - 2 + 2 + 3 - + True - True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Computer's name +leave blank for the +local computer - 1 - 2 1 2 @@ -307,31 +315,38 @@ - + True + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Computer's name -leave blank for the -local computer + 1 + 2 1 2 - + True + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Socket location -Leave blank for -the default socket - 2 - 3 + 1 + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Computer's description +This is a Human redable +name for the computer + + 1 ==== //depot/projects/soc2007/andrew-update/frontend/facund/computer.py#14 (text+ko) ==== @@ -53,7 +53,7 @@ self.__dirs = [] self.__connected = False self.__connection = None - self.__commands = ['Avaliable', 'Installed'] + self.__commands = ['Avaliable', 'Installed', 'Services'] def __str__(self): return self.__name + ": " + (self.__host or self.__socket) @@ -91,6 +91,8 @@ return self.getUpdateList(dir) elif self.__commands[command] == 'Installed': return self.getInstalledList(dir) + elif self.__commands[command] == 'Services': + return self.getServicesList(dir) else: print 'TODO: Handle this command (%d)' % (command,); @@ -119,8 +121,16 @@ # Wait for the response call.acquireLock() call.releaseLock() - print call.getResponse() - + return call.getResponse() + + def restartService(self, dir, service): + args = self.buildInstallArg(dir, service) + call = facund.Call("restart_services", args) + self.__connection.doCall(call) + # Wait for the response + call.acquireLock() + call.releaseLock() + return call.getResponse() def getUpdateList(self, dir = None): if dir is None: @@ -154,6 +164,16 @@ call.releaseLock() return call.getResponse() + def getServicesList(self, dir): + arg = facund.String(dir) + call = facund.Call("get_services", arg) + self.__connection.doCall(call) + # Wait for the response + call.acquireLock() + call.releaseLock() + return call.getResponse() + + def connect(self): '''Connects to the remote computer''' if self.__connection is not None: ==== //depot/projects/soc2007/andrew-update/frontend/facund/controller.py#7 (text+ko) ==== @@ -34,6 +34,8 @@ self.__currentDirectory = None self.__updateModel = updateModel self.__view.setUpdateViewModel(self.__updateModel) + self.__inServices = False + self.__selectedUpdate = None def run(self): self.__view.run() @@ -41,12 +43,18 @@ def onComputerTreeSelect(self, position): self.__currentDirectory = None self.__updateModel.empty() + self.__inServices = False + self.__selectedUpdate = None computer = self.__computersModel.getComputer(position[0]) self.__view.setConnected(computer.getConnectionStatus()) if computer.getConnectionStatus() is not True: self.__view.setInstallable(False, False) + # We can disable the restart button as it will be + # enabled only when we select a service to start + self.__view.setRestartable(False) + self.__currentComputer = computer if len(position) == 1: @@ -65,21 +73,33 @@ # We can't to an install or remove when we have nothing self.__view.setInstallable(False, False) return - item = data.getData()[0] - # Each item will be a pair of - pair = item.getData() - theDir = pair[0].getData() + + if command is 'Services': + self.__inServices = True + for service in data.getData(): + self.__updateModel.addUpdate(service) + else: + item = data.getData()[0] + # Each item will be a pair of + pair = item.getData() + theDir = pair[0].getData() + + for update in pair[1].getData(): + self.__updateModel.addUpdate(update) - for update in pair[1].getData(): - self.__updateModel.addUpdate(update) + if self.__updateModel.getSize() > 0: + if command == "Avaliable": + self.__view.setInstallable(True, False) + elif command == "Installed": + self.__view.setInstallable(False, True) + else: + self.__view.setInstallable(False, False) - if self.__updateModel.getSize() > 0: - if command == "Avaliable": - self.__view.setInstallable(True, False) - elif command == "Installed": - self.__view.setInstallable(False, True) - else: - self.__view.setInstallable(False, False) + def onSelectUpdate(self, item): + if not self.__inServices: + return + self.__selectedUpdate = self.__updateModel.getUpdate(item) + self.__view.setRestartable(True) def getCurrentComputer(self): return self.__currentComputer @@ -87,6 +107,9 @@ def getCurrentDirectory(self): return self.__currentDirectory + def getCurrentService(self): + return self.__selectedUpdate + def installUpdates(self, updates): computer = self.getCurrentComputer() computer.installUpdates(True, updates) @@ -94,3 +117,7 @@ def removeUpdates(self, updates): computer = self.getCurrentComputer() computer.installUpdates(False, updates) + + def restartService(self, dir, service): + computer = self.getCurrentComputer() + computer.restartService(dir, service) ==== //depot/projects/soc2007/andrew-update/frontend/facund/data.py#4 (text+ko) ==== @@ -26,8 +26,6 @@ import struct -#TODO: Create an exception class(es) for bad data, etc - class Object: def __init__(self, type): self.__parent = None @@ -53,6 +51,9 @@ def getData(self): return self.__data + def getType(self): + return self.__type + class Bool(Object): def __init__(self, data = None): Object.__init__(self, "bool") ==== //depot/projects/soc2007/andrew-update/frontend/facund/gui/main_window.py#12 (text+ko) ==== @@ -119,12 +119,16 @@ installButton.connect('clicked', self.onInstallClick) removeButton = self.__xml.get_widget('deinstallButton') removeButton.connect('clicked', self.onRemoveClick) + restartButton = self.__xml.get_widget('restartButton') + restartButton.connect('clicked', self.onRestartClick) def setUpdateViewModel(self, model): '''Sets the model to use to for the computer tree''' self.__updateViewModel = model treeView = self.__xml.get_widget('updateView') treeView.set_model(model) + treeView.connect('cursor-changed', self.onSelectUpdate) + cell = gtk.CellRendererText() column = gtk.TreeViewColumn("Update", cell, text=0) treeView.append_column(column) @@ -160,6 +164,9 @@ deinstallButton = self.__xml.get_widget('deinstallButton') deinstallButton.set_sensitive(uninstallable) + def setRestartable(self, restartable): + restartButton = self.__xml.get_widget('restartButton') + restartButton.set_sensitive(restartable) def onConnectClick(self, widget): '''Signal handler for the connect button''' @@ -190,11 +197,20 @@ dir = self.__controller.getCurrentDirectory() self.__controller.removeUpdates((dir.getName(), 'base')) + def onRestartClick(self, widget): + dir = self.__controller.getCurrentDirectory() + service = self.__controller.getCurrentService() + self.__controller.restartService(dir.getName(), service) + def onSelectComputer(self, widget): '''Signal handler for when the selected item is changed''' cursor = widget.get_cursor() self.__controller.onComputerTreeSelect(cursor[0]) + def onSelectUpdate(self, widget): + cursor = widget.get_cursor() + self.__controller.onSelectUpdate(cursor[0][0]) + def run(self): '''Displays the main window. Does't return''' self.__widget.show() ==== //depot/projects/soc2007/andrew-update/frontend/facund/gui/update_model.py#3 (text+ko) ==== @@ -39,6 +39,10 @@ self.set(iter, 0, name) self.__size += 1 + def getUpdate(self, item): + iter = self.get_iter((item,)) + return self.get_value(iter, 0); + def empty(self): self.__size = 0 self.clear() ==== //depot/projects/soc2007/andrew-update/frontend/facund/network/__init__.py#14 (text+ko) ==== @@ -54,7 +54,7 @@ self.socket.connect(server) def isOpen(self): - return true + return True def read(self, len): return self.socket.recv(len)