Merge branch 'master' of ssh://git.planet-lab.org/git/plstackapi
authorScott Baker <smbaker@gmail.com>
Wed, 6 Aug 2014 18:27:44 +0000 (11:27 -0700)
committerScott Baker <smbaker@gmail.com>
Wed, 6 Aug 2014 18:27:44 +0000 (11:27 -0700)
observer-initscript [new file with mode: 0644]
opencloud.spec
planetstack/core/admin.py
planetstack/core/context_processors.py
planetstack/core/fixtures/initial_data.json
planetstack/core/static/planetstack.css
planetstack/ec2_observer/syncstep.py
planetstack/planetstack/urls.py
planetstack/templates/admin/core/slice/change_form.html [new file with mode: 0644]
planetstack/templates/admin/login.html

diff --git a/observer-initscript b/observer-initscript
new file mode 100644 (file)
index 0000000..d948eac
--- /dev/null
@@ -0,0 +1,63 @@
+#!/bin/bash
+#
+# observer       Starts and stops Observer daemon
+#
+
+# Source function library.
+. /etc/init.d/functions
+
+[ -f /etc/sysconfig/plstackobserver ] && . /etc/sysconfig/plstackobserver
+
+
+plstackobserver=${NODEMANAGER-"python /opt/planetstack/planetstack-backend.py -d"}
+prog="OpenCloud Observer"
+pidfile=${PIDFILE-/var/run/plstackobserver.pid}
+
+RETVAL=0
+
+function start() {
+    action $"Starting $prog: " daemon --pidfile=$pidfile --check=plstackobserver $plstackobserver "$@"
+}
+
+function stop() {
+    action $"Stopping $prog: " killproc -p $pidfile plstackobserver
+}
+
+case "$1" in
+    start)
+       start $options
+       ;;
+    stop)
+       stop
+       ;;
+    status)
+       status -p $pidfile plstackobserver
+       RETVAL=$?
+       ;;
+    restart|reload)
+       shift
+       stop
+       start $options "$@"
+       ;;
+    condrestart)
+       shift
+       [ -f ${pidfile} ] && { stop; start $options "$@"; }
+       ;;
+    restartverbose)
+       shift
+       stop
+       $plstackobserver $verboseoptions "$@"
+       ;;
+    restartdebug)
+       shift
+       stop
+       echo "Restarting with $debugoptions $@ .."
+       $plstackobserver $debugoptions "$@"
+       ;;
+    *)
+       echo $"Usage: $0 {start|stop|status|restart|condrestart|restartdebug [-d]}"
+       exit 1
+       ;;
+esac
+
+exit $RETVAL
index 184cbf8..26f67f8 100644 (file)
@@ -70,12 +70,15 @@ fi
 rm -rf %{buildroot}
 mkdir -p  %{buildroot}
 install -d %{buildroot}/opt/planetstack
+install -d %{buildroot}/etc/init.d
 
 # in builddir
 cp -rp ./planetstack %{buildroot}/opt/.
+cp observer-initscript %{buildroot}/etc/init.d/plstackobserver
 
 find %{buildroot}/opt/planetstack -type f -print | sed "s@^$RPM_BUILD_ROOT@@g" > %{_tmppath}/tmp-filelist
 cp %{_tmppath}/tmp-filelist /tmp/tmp-filelist
+echo /etc/init.d/plstackobserver > %{_tmppath}/tmp-filelist
 
 %clean
 rm -rf %{buildroot}
index 8e81b4b..9f8fbb0 100644 (file)
@@ -234,6 +234,13 @@ class SliverInline(PlStackTabularInline):
     def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
         if db_field.name == 'deploymentNetwork':
            kwargs['queryset'] = Deployment.select_by_acl(request.user)
+           # the inscrutable jquery selector below says:
+           #     find the closest parent "tr" to the current element
+           #     then find the child with class "field-node"
+           #     then find the child with that is a select
+           #     then return its id
+           kwargs['widget'] = forms.Select(attrs={'onChange': "update_nodes(this, $($(this).closest('tr')[0]).find('.field-node select')[0].id)"})
+           #kwargs['widget'] = forms.Select(attrs={'onChange': "console.log($($($(this).closest('tr')[0]).children('.field-node')[0]).children('select')[0].id);"})
 
         field = super(SliverInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
 
@@ -760,6 +767,19 @@ class SliceAdmin(PlanetStackBaseAdmin):
         ('reservations','Reservations'),
     )
 
+    def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
+        #deployment_nodes = {}
+        #for node in Node.objects.all():
+        #    deployment_nodes[node.deployment.id] = get(deployment_nodes, node.deployment.id, []).append( (node.id, node.name) )
+
+        deployment_nodes = []
+        for node in Node.objects.all():
+            deployment_nodes.append( (node.deployment.id, node.id, node.name) )
+
+        context["deployment_nodes"] = deployment_nodes
+
+        return super(SliceAdmin, self).render_change_form(request, context, add, change, form_url, obj)
+
     def formfield_for_foreignkey(self, db_field, request, **kwargs):
         if db_field.name == 'site':
             kwargs['queryset'] = Site.select_by_user(request.user)
index 270ec4e..9cfcaa6 100644 (file)
@@ -1,4 +1,14 @@
 from django.conf import settings
+from core.models import Site
+
 
 def planetstack(request):
-    return {"DISABLE_MINIDASHBOARD": settings.DISABLE_MINIDASHBOARD}
+    allSites = []
+    for site in Site.objects.all():
+        allowNewUsers = True    # replace with logic for blessing sites for registration, if necessary
+        allSites.append( {"name": site.name,
+                           "id": site.id,
+                           "allowNewUsers": allowNewUsers} )
+
+    return {"DISABLE_MINIDASHBOARD": settings.DISABLE_MINIDASHBOARD,
+            "sites": allSites}
index 1c81b7e..c5c754f 100644 (file)
         "created": "2014-04-22T11:34:39.770Z"
     }
 },
+{
+    "pk": 5,
+    "model": "core.siterole",
+    "fields": {
+        "updated": "2014-04-22T11:34:39.770Z",
+        "enacted": null,
+        "role": "default",
+        "created": "2014-04-22T11:34:39.770Z"
+    }
+},
 {
     "pk": 5, 
     "model": "core.deployment", 
index 44d62b4..8fb6e86 100644 (file)
@@ -496,13 +496,13 @@ padding-left: 8px;
 display:none;
 }
 
-.login #content-main form input[type=text]{
+.login #content-main form input[type=text], .requestDialog.ui-widget input{
 width: 94%;
 padding:4px 6px;
 border-radius: 0px;
 height: 30px;
-background-color: #E5E5E5;
-background-image: url('name.png');
+background-color: rgb(250, 255, 189);
+/*background-image: url('name.png');*/
 background-repeat: no-repeat;
 background-position: 95%;
 font-size: 12px;
@@ -671,11 +671,18 @@ height: 84.5%;
        float: left;
 }
 
-.createAccountLink {
+#request-account-form{
+       display:none;
+}
+
+#requestAccountLink {
        width: 55%;
        text-align: right;
        float: left;
-       
+       padding-left: 21%;
+       cursor: pointer;
+       color: #448CCA;
+       text-decoration: underline;     
 }
 
 .login .btn-info {
@@ -1031,6 +1038,15 @@ div.chartContainer
  margin-left: 5%;
 }
 
+
+#adv-slice-image-value{
+margin-right: 0.5%;
+}
+
+#adv-network-value {
+margin-right: 0.3%;
+}
+
 #network-dropdown,#adv-network-dropdown,#adv-network-value{
  margin-left: 3.7%;
 }
@@ -1043,16 +1059,16 @@ div.chartContainer
    margin-left: 2%;
 }
 #adv-dataset-dropdown{
-margin-left: 3%;
+margin-left: 3.7%;
 }
 #advanced-tenant,#basic-tenant,#sliver-btn,#save-btn{
   float:right;
 }
- #delete-slice-btn,#download-details{
+ #delete-slice-btn,#download-details,#add-user-btn{
        margin-left:1%;
 }
 
-#sliver-btn,#save-btn,#create-slice-btn,#delete-slice-btn,#download-details{
+#sliver-btn,#save-btn,#create-slice-btn,#delete-slice-btn,#add-user-btn,#download-details{
   margin-top:1%;
 }
 
@@ -1138,12 +1154,64 @@ display:none;
 
 #private-vol{
 margin-right: 15% !important;
-}\r
-\r
-.customize_row {\r
-  display: table;\r
-}\r
-.customize_column {\r
-  display: table-cell;\r
-  padding: 10px;\r
-}\r
+}
+.customize_row {
+  display: table;
+}
+.customize_column {
+  display: table-cell;
+  padding: 10px;
+}
+
+.request-form-row{
+padding:1% 8%;
+}
+
+.requestDialog{
+background-color: white;
+border-radius: 8px;
+width: 30% !important;
+height: 40% !important;
+margin-top: -16%;
+top: -103.703125px !important;
+}
+
+.request-form-row label{
+       float: left;
+}
+
+
+.requestDialog .ui-dialog-buttonset .ui-button{
+border-radius: 0 !important;
+background-color: grey !important;
+font-weight: bold !important;
+font-size: 0.9em; !important
+}
+
+.requestDialog .ui-dialog-titlebar-close{
+float:right;
+}
+
+#request-signup{
+height: 40px !important;
+margin: 0 14%;
+float: left;
+background-color: #448CCA;
+background-image: none;
+width: 70% !important;
+}
+
+.requestDialog .ui-dialog-titlebar{
+border-radius: 0 !important;
+height: 25px;
+padding-top: 2%;
+}
+
+.requestDialog #ui-id-1{
+padding-left: 28%;
+font-size: medium;
+}
+
+#request-site-name{
+       width: 98%;
+}
index dcfea7d..d5f7523 100644 (file)
@@ -60,7 +60,10 @@ class SyncStep:
         for dep in self.dependencies:
             peer_name = dep[0].lower() + dep[1:]    # django names are camelCased with the first letter lower
             peer_object = getattr(obj, peer_name)
-            if (peer_object.pk==failed.pk):
+            
+            # peer_object can be None, and if so there
+            # is no object-level dependency
+            if (peer_object and peer_object.pk==failed.pk):
                 raise FailedDependency
 
     def call(self, failed=[], deletion=False):
index 3513a38..929505d 100644 (file)
@@ -114,7 +114,7 @@ urlpatterns = patterns('',
     url(r'^plstackapi/users/$', UserList.as_view(), name='user-list'),
     url(r'^plstackapi/users/(?P<pk>[a-zA-Z0-9_\-]+)/$', UserDetail.as_view(), name='user-detail'),
 
-    url(r'^legacyapi/$', 'core.views.legacyapi.LegacyXMLRPC', name='xmlrpc'),
+    url(r'^xmlrpc/legacyapi/$', 'core.views.legacyapi.LegacyXMLRPC', name='xmlrpc'),
 
 #    url(r'^analytics/(?P<name>\w+)/$', AnalyticsAjaxView.as_view(), name="analytics"),
 
diff --git a/planetstack/templates/admin/core/slice/change_form.html b/planetstack/templates/admin/core/slice/change_form.html
new file mode 100644 (file)
index 0000000..c94b580
--- /dev/null
@@ -0,0 +1,26 @@
+{% extends 'admin/change_form.html' %}
+{% block extrahead %} 
+{{ block.super }} 
+<script>
+deployment_nodes = [
+{% for dn in deployment_nodes %}
+   [{{ dn.0 }}, {{ dn.1 }} , "{{ dn.2 }}"],
+{% endfor %}
+];
+
+function update_nodes(deployment_select, node_select_id) {
+    deployment_id = $(deployment_select).val();
+    html = "<option value=''>---------</option>\n";
+    for (i in deployment_nodes) {
+        dn = deployment_nodes[i];
+        if (dn[0] == deployment_id) {
+            html = html + '<option value="' + dn[1] + '">' + dn[2] + '</option>\n'
+        }
+    }
+    //console.log(html);
+    $("#"+node_select_id).empty().append(html);
+}
+</script>
+
+{% endblock %}
+
index b04f842..a165707 100644 (file)
@@ -4,8 +4,11 @@
 {% block extrastyle %}{{ block.super }}
 <link rel="stylesheet" type="text/css" href="/static/suit/bootstrap/css/bootstrap.min.css" media="all"/>
 <link rel="stylesheet" type="text/css" href="{% static "planetstack.css" %}" />
+<script src="{% static 'suit/js/jquery-1.9.1.min.js' %}"></script>
+<script src="http://code.jquery.com/ui/1.11.0/jquery-ui.js"></script>
 {% endblock %}
 
+
 {% block bodyclass %}login{% endblock %}
 
 {% block nav-global %}{% endblock %}
     <input type="hidden" name="this_is_the_login_form" value="1" />
     <input type="hidden" name="next" value="{{ next }}" />
   </div>
-  {% url 'admin_password_reset' as password_reset_url %}
-  {% if password_reset_url %}
-  <div class="password-reset-link">
-    <a href="{{ password_reset_url }}">{% trans 'Forgotten your password or username?' %}</a>
-  </div>
-  {% endif %}
   <div class="submit-row">
     <input type="submit" class="btn btn-info" value="{% trans 'SIGN IN' %}" />
   </div>
-{% url 'django-admindocs-docroot' as docsroot %}
-                  {% if docsroot %}
-<div class="createAccountLink"><a href="{{ docsroot }}">{% trans 'Request a new Account' %}</a></div>
-
-                  {% endif %}
+        <div id="requestAccountLink">{% trans 'Request a new Account' %}</div>
 </form>
+
+<div id="request-account-form" title="Request an Account" style="display: none;">
+       <form>
+               <fieldset>
+                       <div class="request-form-row">
+                               <label for="request-first-name">First Name</label>
+                               <input type="text" name="request-first-name" id="request-first-name">
+                       </div>
+                        <div class="request-form-row">
+                                <label for="request-last-name">Last Name</label>
+                                <input type="text" name="request-last-name" id="request-last-name">
+                        </div>
+                        <div class="request-form-row">
+                                <label for="request-email">Email</label>
+                                <input type="text" name="request-email" id="request-email">
+                        </div>
+                        <div class="request-form-row">
+                                <label for="request-site-name">Site</label><br>
+                               <select id="request-site-name" name="request-site-name">
+                                    <option>---------</option>
+                                    {% for site in sites %}
+                                        {% if site.allowNewUsers %}
+                                            <option>{{ site.name }}</option>
+                                        {% endif %}
+                                    {% endfor %}
+                               </select>
+                        </div>
+                       <div class="submit-row">
+                               <input id ="request-signup" class="btn btn-info" value="SIGN UP">
+                       </div>
+               </fieldset>
+       </form>
+</div>
+</div>
+</div>
+
+
 <script type="text/javascript">
+$(function() {
+       initRequest();
+});
+function initRequest(){
+       $.ajax({
+                       url: '/tenantview',
+                       dataType: 'json',
+                       success: function (data) {
+                               var sites = data['sitesToBeRequested'];
+                               console.log(sites);
+                               for (site in sites){
+                                       $("#request-site-name").append("<option>" + site + "</option>");
+                               }
+                       }
+               });
+}
+$("#requestAccountLink").unbind().click(function(){
+       $("#request-account-form").dialog({
+                                       autoOpen: false,
+                                       modal: true,
+                                       dialogClass: "requestDialog",
+                               });
+                               $("#request-account-form").dialog("open");
+})
+$("#request-signup").unbind().click(function(){
+                                                       $.ajax({
+                                                               url: '/requestaccess/',
+                                                               dataType: 'json',
+                                                               data: {
+                                                                       email: $("#request-email").val(),
+                                                                       firstname: $("#request-first-name").val(),
+                                                                       lastname: $("#request-last-name").val(),
+                                                                       site: $("#request-site-name").val(),
+                                                                       csrfmiddlewaretoken: "{{ csrf_token }}", // < here 
+                                                                       state: "inactive"
+                                                               },
+                                                               async: false,
+                                                               type: 'POST',
+                                                               success: function () {
+                                                                       $("#request-account-form").dialog("close");     
+                                                                       alert("Your request has been submitted");                                                       
+                                                               },
+                                                               error:function (xhr, textStatus, thrownError){
+                                                                  alert("Error:", textStatus + " " + xhr.responseText);
+                                                               }
+                                                       });
+})
 document.getElementById('id_username').focus()
 </script>
 </div>