Revision eb765213

b/Changelog
30 30

  
31 31
* Implement API calls for projects.
32 32

  
33
* Store the base URL of a component. Deployer should provide it when adding
34
  a new component. Service endpoints originating from a component are
35
  expected to match its base URL; otherwise, a warning is issued.
36
  Re-registration with `snf-component-register' affects both the base and
37
  the ui URL.
38

  
39
* Management commands:
40
  * Changed commands:
41
     * component-add got options --base-url and --ui-url
42

  
33 43
Cyclades
34 44
--------
35 45

  
b/docs/quick-install-admin-guide.rst
917 917

  
918 918
    .. code-block:: console
919 919

  
920
       astakos-host$ snf-manage component-add astakos astakos_ui_url
921
       astakos-host$ snf-manage component-add cyclades cyclades_ui_url
922
       astakos-host$ snf-manage component-add pithos pithos_ui_url
920
       astakos-host$ snf-manage component-add astakos --base-url astakos_base_url --ui-url astakos_ui_url
921
       astakos-host$ snf-manage component-add cyclades --base-url cyclades_base_url --ui-url cyclades_ui_url
922
       astakos-host$ snf-manage component-add pithos --base-url pithos_base_url --ui-url pithos_ui_url
923 923
       astakos-host$ snf-manage service-export-astakos > astakos.json
924 924
       astakos-host$ snf-manage service-import --json astakos.json
925 925
       cyclades-host$ snf-manage service-export-cyclades > cyclades.json
b/docs/upgrade/upgrade-0.15.rst
7 7

  
8 8
2. Upgrade packages, migrate the databases and configure settings.
9 9

  
10
3. Bring up all services.
10
3. Re-register components and services in astakos.
11

  
12
4. Bring up all services.
11 13

  
12 14
.. warning::
13 15

  
......
100 102

  
101 103
    pithos-host$ pithos-migrate upgrade head
102 104

  
103
3. Bring all services up
105
3. Re-register components and services in astakos
106
=================================================
107

  
108
Component registration has changed; you will thus need to repeat the
109
process. On the astakos node, run::
110

  
111
    astakos-host$ snf-component-register
112

  
113
This will detect that the Synnefo components are already registered and ask
114
to re-register. Answer positively. You need to enter the base URL and the UI
115
URL for each component, just like during the initial registration.
116

  
117
4. Bring all services up
104 118
========================
105 119

  
106 120
After the upgrade is finished, we bring up all services:
b/snf-astakos-app/astakos/im/management/commands/component-add.py
31 31
# interpreted as representing official policies, either expressed
32 32
# or implied, of GRNET S.A.
33 33

  
34
from optparse import make_option
34 35
from django.core.management.base import BaseCommand, CommandError
35 36
from astakos.im.models import Component
36 37

  
37 38

  
38 39
class Command(BaseCommand):
39
    args = "<name> <component URL>"
40
    args = "<name>"
40 41
    help = "Register a component"
41 42

  
43
    option_list = BaseCommand.option_list + (
44
        make_option('--ui-url',
45
                    dest='ui_url',
46
                    default=None,
47
                    help="Set UI URL"),
48
        make_option('--base-url',
49
                    dest='base_url',
50
                    default=None,
51
                    help="Set base URL"),
52
    )
53

  
42 54
    def handle(self, *args, **options):
43
        if len(args) < 2:
55
        if len(args) != 1:
44 56
            raise CommandError("Invalid number of arguments")
45 57

  
46 58
        name = args[0]
47
        url = args[1]
59
        base_url = options['base_url']
60
        ui_url = options['ui_url']
61

  
48 62
        try:
49
            s = Component.objects.get(name=name)
63
            Component.objects.get(name=name)
50 64
            m = "There already exists a component named '%s'." % name
51 65
            raise CommandError(m)
52 66
        except Component.DoesNotExist:
53 67
            pass
54 68

  
55
        components = list(Component.objects.filter(url=url))
56
        if components:
57
            m = "Component URL '%s' is registered for another service." % url
58
            raise CommandError(m)
59

  
60 69
        try:
61
            c = Component.objects.create(name=name, url=url)
70
            c = Component.objects.create(
71
                name=name, url=ui_url, base_url=base_url)
62 72
        except BaseException:
63 73
            raise CommandError("Failed to register component.")
64 74
        else:
b/snf-astakos-app/astakos/im/management/commands/component-list.py
42 42
    FIELDS = {
43 43
        "id": ("id", "Component ID"),
44 44
        "name": ("name", "Component Name"),
45
        "url": ("url", "Component URL"),
45
        "base url": ("base_url", "Component base URL"),
46
        "ui url": ("url", "Component UI URL"),
46 47
        "token": ("auth_token", "Authentication token"),
47 48
        "token created": ("auth_token_created", "Token creation date"),
48 49
    }
49 50

  
50
    fields = ["id", "name", "url", "token"]
51
    fields = ["id", "name", "base url"]
b/snf-astakos-app/astakos/im/management/commands/component-modify.py
1
# Copyright 2012 GRNET S.A. All rights reserved.
1
# Copyright 2012, 2013 GRNET S.A. All rights reserved.
2 2
#
3 3
# Redistribution and use in source and binary forms, with or
4 4
# without modification, are permitted provided that the following
......
43 43
    help = "Modify component attributes"
44 44

  
45 45
    option_list = BaseCommand.option_list + (
46
        make_option('--url',
47
                    dest='url',
46
        make_option('--ui-url',
47
                    dest='ui_url',
48 48
                    default=None,
49
                    help="Set component url"),
49
                    help="Set UI URL"),
50
        make_option('--base-url',
51
                    dest='base_url',
52
                    help="Set base URL"),
50 53
        make_option('--auth-token',
51 54
                    dest='auth_token',
52 55
                    default=None,
......
79 82
                "Component does not exist. You may run snf-manage "
80 83
                "component-list for available component IDs.")
81 84

  
82
        url = options.get('url')
85
        ui_url = options.get('ui_url')
86
        base_url = options.get('base_url')
83 87
        auth_token = options.get('auth_token')
84 88
        renew_token = options.get('renew_token')
85 89
        purge_services = options.get('purge_services')
86 90

  
87
        if not any([url, auth_token, renew_token, purge_services]):
91
        if not any([ui_url, base_url, auth_token, renew_token,
92
                    purge_services]):
88 93
            raise CommandError("No option specified.")
89 94

  
90
        if url:
91
            component.url = url
95
        if ui_url:
96
            component.url = ui_url
97

  
98
        if base_url:
99
            component.base_url = base_url
92 100

  
93 101
        if auth_token:
94 102
            component.auth_token = auth_token
b/snf-astakos-app/astakos/im/management/commands/service-import.py
90 90
                raise CommandError(m)
91 91

  
92 92
            try:
93
                existed = add_service(component, name, service_type, endpoints)
93
                existed = add_service(component, name, service_type, endpoints,
94
                                      out=self.stdout)
94 95
            except RegisterException as e:
95 96
                raise CommandError(e.message)
96 97

  
b/snf-astakos-app/astakos/im/migrations/0053_auto__add_field_component_base_url.py
1
# encoding: utf-8
2
import datetime
3
from south.db import db
4
from south.v2 import SchemaMigration
5
from django.db import models
6

  
7
class Migration(SchemaMigration):
8

  
9
    def forwards(self, orm):
10
        
11
        # Adding field 'Component.base_url'
12
        db.add_column('im_component', 'base_url', self.gf('django.db.models.fields.CharField')(max_length=1024, null=True), keep_default=False)
13

  
14

  
15
    def backwards(self, orm):
16
        
17
        # Deleting field 'Component.base_url'
18
        db.delete_column('im_component', 'base_url')
19

  
20

  
21
    models = {
22
        'auth.group': {
23
            'Meta': {'object_name': 'Group'},
24
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
25
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
26
            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
27
        },
28
        'auth.permission': {
29
            'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
30
            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
31
            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
32
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
33
            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
34
        },
35
        'auth.user': {
36
            'Meta': {'object_name': 'User'},
37
            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
38
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
39
            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
40
            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
41
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
42
            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
43
            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
44
            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
45
            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
46
            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
47
            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
48
            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
49
            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
50
        },
51
        'contenttypes.contenttype': {
52
            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
53
            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
54
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
55
            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
56
            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
57
        },
58
        'im.additionalmail': {
59
            'Meta': {'object_name': 'AdditionalMail'},
60
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
61
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
62
            'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
63
        },
64
        'im.approvalterms': {
65
            'Meta': {'object_name': 'ApprovalTerms'},
66
            'date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
67
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
68
            'location': ('django.db.models.fields.CharField', [], {'max_length': '255'})
69
        },
70
        'im.astakosuser': {
71
            'Meta': {'object_name': 'AstakosUser', '_ormbases': ['auth.User']},
72
            'accepted_email': ('django.db.models.fields.EmailField', [], {'default': 'None', 'max_length': '75', 'null': 'True', 'blank': 'True'}),
73
            'accepted_policy': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
74
            'activation_sent': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
75
            'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
76
            'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
77
            'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
78
            'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
79
            'date_signed_terms': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
80
            'deactivated_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
81
            'deactivated_reason': ('django.db.models.fields.TextField', [], {'default': 'None', 'null': 'True'}),
82
            'disturbed_quota': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
83
            'email_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
84
            'has_credits': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
85
            'has_signed_terms': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
86
            'invitations': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
87
            'is_rejected': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
88
            'is_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
89
            'level': ('django.db.models.fields.IntegerField', [], {'default': '4'}),
90
            'moderated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
91
            'moderated_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
92
            'moderated_data': ('django.db.models.fields.TextField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
93
            'policy': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.Resource']", 'null': 'True', 'through': "orm['im.AstakosUserQuota']", 'symmetrical': 'False'}),
94
            'rejected_reason': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
95
            'updated': ('django.db.models.fields.DateTimeField', [], {}),
96
            'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
97
            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '255', 'unique': 'True', 'null': 'True'}),
98
            'verification_code': ('django.db.models.fields.CharField', [], {'max_length': '255', 'unique': 'True', 'null': 'True'}),
99
            'verified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
100
        },
101
        'im.astakosuserauthprovider': {
102
            'Meta': {'ordering': "('module', 'created')", 'unique_together': "(('identifier', 'module', 'user'),)", 'object_name': 'AstakosUserAuthProvider'},
103
            'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
104
            'affiliation': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
105
            'auth_backend': ('django.db.models.fields.CharField', [], {'default': "'astakos'", 'max_length': '255'}),
106
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
107
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
108
            'identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
109
            'info_data': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
110
            'module': ('django.db.models.fields.CharField', [], {'default': "'local'", 'max_length': '255'}),
111
            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_providers'", 'to': "orm['im.AstakosUser']"})
112
        },
113
        'im.astakosuserquota': {
114
            'Meta': {'unique_together': "(('resource', 'user'),)", 'object_name': 'AstakosUserQuota'},
115
            'capacity': ('snf_django.lib.db.fields.IntDecimalField', [], {'max_digits': '38', 'decimal_places': '0'}),
116
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
117
            'resource': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Resource']"}),
118
            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
119
        },
120
        'im.authproviderpolicyprofile': {
121
            'Meta': {'ordering': "['priority']", 'object_name': 'AuthProviderPolicyProfile'},
122
            'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
123
            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'authpolicy_profiles'", 'symmetrical': 'False', 'to': "orm['auth.Group']"}),
124
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
125
            'is_exclusive': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
126
            'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
127
            'policy_add': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
128
            'policy_automoderate': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
129
            'policy_create': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
130
            'policy_limit': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'}),
131
            'policy_login': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
132
            'policy_remove': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
133
            'policy_required': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
134
            'policy_switch': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
135
            'priority': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
136
            'provider': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
137
            'users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'authpolicy_profiles'", 'symmetrical': 'False', 'to': "orm['im.AstakosUser']"})
138
        },
139
        'im.chain': {
140
            'Meta': {'object_name': 'Chain'},
141
            'chain': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
142
        },
143
        'im.component': {
144
            'Meta': {'object_name': 'Component'},
145
            'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
146
            'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
147
            'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
148
            'base_url': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
149
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
150
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
151
            'url': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'})
152
        },
153
        'im.emailchange': {
154
            'Meta': {'object_name': 'EmailChange'},
155
            'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
156
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
157
            'new_email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
158
            'requested_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
159
            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emailchanges'", 'unique': 'True', 'to': "orm['im.AstakosUser']"})
160
        },
161
        'im.endpoint': {
162
            'Meta': {'object_name': 'Endpoint'},
163
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
164
            'service': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'endpoints'", 'to': "orm['im.Service']"})
165
        },
166
        'im.endpointdata': {
167
            'Meta': {'unique_together': "(('endpoint', 'key'),)", 'object_name': 'EndpointData'},
168
            'endpoint': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'data'", 'to': "orm['im.Endpoint']"}),
169
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
170
            'key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
171
            'value': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
172
        },
173
        'im.invitation': {
174
            'Meta': {'object_name': 'Invitation'},
175
            'code': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
176
            'consumed': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
177
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
178
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
179
            'inviter': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'invitations_sent'", 'null': 'True', 'to': "orm['im.AstakosUser']"}),
180
            'is_consumed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
181
            'realname': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
182
            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
183
        },
184
        'im.pendingthirdpartyuser': {
185
            'Meta': {'unique_together': "(('provider', 'third_party_identifier'),)", 'object_name': 'PendingThirdPartyUser'},
186
            'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
187
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
188
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
189
            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}),
190
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
191
            'info': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
192
            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}),
193
            'provider': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
194
            'third_party_identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
195
            'token': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
196
            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
197
        },
198
        'im.project': {
199
            'Meta': {'object_name': 'Project'},
200
            'application': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'project'", 'unique': 'True', 'to': "orm['im.ProjectApplication']"}),
201
            'creation_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
202
            'id': ('django.db.models.fields.BigIntegerField', [], {'primary_key': 'True', 'db_column': "'id'"}),
203
            'members': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.AstakosUser']", 'through': "orm['im.ProjectMembership']", 'symmetrical': 'False'}),
204
            'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'unique': 'True', 'null': 'True', 'db_index': 'True'}),
205
            'state': ('django.db.models.fields.IntegerField', [], {'default': '1', 'db_index': 'True'})
206
        },
207
        'im.projectapplication': {
208
            'Meta': {'unique_together': "(('chain', 'id'),)", 'object_name': 'ProjectApplication'},
209
            'applicant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'projects_applied'", 'to': "orm['im.AstakosUser']"}),
210
            'chain': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'chained_apps'", 'db_column': "'chain'", 'to': "orm['im.Project']"}),
211
            'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
212
            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
213
            'end_date': ('django.db.models.fields.DateTimeField', [], {}),
214
            'homepage': ('django.db.models.fields.URLField', [], {'max_length': '255', 'null': 'True'}),
215
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
216
            'issue_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
217
            'limit_on_members_number': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
218
            'member_join_policy': ('django.db.models.fields.IntegerField', [], {}),
219
            'member_leave_policy': ('django.db.models.fields.IntegerField', [], {}),
220
            'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
221
            'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'projects_owned'", 'to': "orm['im.AstakosUser']"}),
222
            'resource_grants': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['im.Resource']", 'null': 'True', 'through': "orm['im.ProjectResourceGrant']", 'blank': 'True'}),
223
            'response': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
224
            'response_actor': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'responded_apps'", 'null': 'True', 'to': "orm['im.AstakosUser']"}),
225
            'response_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
226
            'start_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
227
            'state': ('django.db.models.fields.IntegerField', [], {'default': '0', 'db_index': 'True'}),
228
            'waive_actor': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'waived_apps'", 'null': 'True', 'to': "orm['im.AstakosUser']"}),
229
            'waive_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
230
            'waive_reason': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
231
        },
232
        'im.projectlock': {
233
            'Meta': {'object_name': 'ProjectLock'},
234
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
235
        },
236
        'im.projectlog': {
237
            'Meta': {'object_name': 'ProjectLog'},
238
            'actor': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']", 'null': 'True'}),
239
            'comments': ('django.db.models.fields.TextField', [], {'null': 'True'}),
240
            'date': ('django.db.models.fields.DateTimeField', [], {}),
241
            'from_state': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
242
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
243
            'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'log'", 'to': "orm['im.Project']"}),
244
            'reason': ('django.db.models.fields.TextField', [], {'null': 'True'}),
245
            'to_state': ('django.db.models.fields.IntegerField', [], {})
246
        },
247
        'im.projectmembership': {
248
            'Meta': {'unique_together': "(('person', 'project'),)", 'object_name': 'ProjectMembership'},
249
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
250
            'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"}),
251
            'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Project']"}),
252
            'state': ('django.db.models.fields.IntegerField', [], {'default': '0', 'db_index': 'True'})
253
        },
254
        'im.projectmembershiplog': {
255
            'Meta': {'object_name': 'ProjectMembershipLog'},
256
            'actor': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']", 'null': 'True'}),
257
            'comments': ('django.db.models.fields.TextField', [], {'null': 'True'}),
258
            'date': ('django.db.models.fields.DateTimeField', [], {}),
259
            'from_state': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
260
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
261
            'membership': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'log'", 'to': "orm['im.ProjectMembership']"}),
262
            'reason': ('django.db.models.fields.TextField', [], {'null': 'True'}),
263
            'to_state': ('django.db.models.fields.IntegerField', [], {})
264
        },
265
        'im.projectresourcegrant': {
266
            'Meta': {'unique_together': "(('resource', 'project_application'),)", 'object_name': 'ProjectResourceGrant'},
267
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
268
            'member_capacity': ('snf_django.lib.db.fields.IntDecimalField', [], {'default': '0', 'max_digits': '38', 'decimal_places': '0'}),
269
            'project_application': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.ProjectApplication']", 'null': 'True'}),
270
            'project_capacity': ('snf_django.lib.db.fields.IntDecimalField', [], {'null': 'True', 'max_digits': '38', 'decimal_places': '0'}),
271
            'resource': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Resource']"})
272
        },
273
        'im.resource': {
274
            'Meta': {'object_name': 'Resource'},
275
            'allow_in_projects': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
276
            'desc': ('django.db.models.fields.TextField', [], {'null': 'True'}),
277
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
278
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
279
            'service_origin': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
280
            'service_type': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
281
            'unit': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
282
            'uplimit': ('snf_django.lib.db.fields.IntDecimalField', [], {'default': '0', 'max_digits': '38', 'decimal_places': '0'})
283
        },
284
        'im.service': {
285
            'Meta': {'object_name': 'Service'},
286
            'component': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Component']"}),
287
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
288
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
289
            'type': ('django.db.models.fields.CharField', [], {'max_length': '255'})
290
        },
291
        'im.sessioncatalog': {
292
            'Meta': {'object_name': 'SessionCatalog'},
293
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
294
            'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
295
            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sessions'", 'null': 'True', 'to': "orm['im.AstakosUser']"})
296
        },
297
        'im.usersetting': {
298
            'Meta': {'unique_together': "(('user', 'setting'),)", 'object_name': 'UserSetting'},
299
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
300
            'setting': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
301
            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"}),
302
            'value': ('django.db.models.fields.IntegerField', [], {})
303
        }
304
    }
305

  
306
    complete_apps = ['im']
b/snf-astakos-app/astakos/im/models.py
124 124
                            db_index=True)
125 125
    url = models.CharField(_('Component url'), max_length=1024, null=True,
126 126
                           help_text=_("URL the component is accessible from"))
127
    base_url = models.CharField(max_length=1024, null=True)
127 128
    auth_token = models.CharField(_('Authentication Token'), max_length=64,
128 129
                                  null=True, blank=True, unique=True)
129 130
    auth_token_created = models.DateTimeField(_('Token creation date'),
b/snf-astakos-app/astakos/im/register.py
121 121
    return resource_dict
122 122

  
123 123

  
124
def add_endpoint(service, endpoint_dict):
124
def add_endpoint(component, service, endpoint_dict, out=None):
125 125
    endpoint = Endpoint.objects.create(service=service)
126 126
    for key, value in endpoint_dict.iteritems():
127
        base_url = component.base_url
128
        if key == "publicURL" and not value.startswith(base_url):
129
            warn = out.write if out is not None else logger.warning
130
            warn("Warning: Endpoint URL '%s' does not start with "
131
                 "assumed component base URL '%s'.\n" % (value, base_url))
127 132
        EndpointData.objects.create(
128 133
            endpoint=endpoint, key=key, value=value)
129 134

  
130 135

  
131
def add_service(component, name, service_type, endpoints):
136
def add_service(component, name, service_type, endpoints, out=None):
132 137
    defaults = {'component': component,
133 138
                'type': service_type,
134 139
                }
......
146 151
        service.save()
147 152

  
148 153
    for endpoint in endpoints:
149
        add_endpoint(service, endpoint)
154
        add_endpoint(component, service, endpoint, out=out)
150 155

  
151 156
    return not created
b/snf-astakos-app/astakos/scripts/snf-component-register
42 42

  
43 43
register_component () {
44 44
    component=$1
45
    exists=$2
45 46
    component_desc=${desc[$component]}
46 47
    component_ex_url=${ex_url[$component]}
47 48
    echo "Registering the $component_desc ($component):"
......
55 56
    read ui_url
56 57
    decide "Register $component with the given URLs (y/n)? "
57 58
    if [ $? -eq 0 ]; then
58
        snf-manage component-add $component $ui_url
59
        if [ $? -eq 0 ]; then
60
            read -p "Please write down the token and press Enter to continue. "
61
            register_services $component $base_url
62
            changed=1
63
            echo
59
        if [ $exists -eq 0 ]; then
60
            snf-manage component-add $component --base-url $base_url \
61
                --ui-url $ui_url
62
            if [ $? -eq 0 ]; then
63
                read -p "Please write down the token and press Enter to continue. "
64
                changed=1
65
            fi
66
        else
67
            snf-manage component-modify $component --base-url $base_url \
68
                --ui-url $ui_url --purge-services
64 69
        fi
65
    fi
66
}
67

  
68
register_comp_serv () {
69
    component=$1
70
    component_desc=${desc[$component]}
71
    component_ex_url=${ex_url[$component]}
72
    echo "Registering services for $component:"
73
    echo "Give the URL of $component base installation" \
74
        "(e.g. $component_ex_url)"
75
    echo -n 'Base URL: '
76
    read base_url
77
    decide "Register ${component}'s services with the given URL (y/n)? "
78
    if [ $? -eq 0 ]; then
79 70
        register_services $component $base_url
80
        echo
81 71
    fi
82 72
}
83 73

  
......
91 81
    if [ $? -ne 0 ]; then
92 82
        decide "Register the ${desc[$component]} ($component) (y/n)? "
93 83
        if [ $? -eq 0 ]; then
94
            register_component $component
84
            register_component $component 0
95 85
        fi
96 86
    else
97 87
        echo "The ${desc[$component]} ($component) is registered."
98
        decide "Update its registered services (y/n)? "
88
        decide "Re-register (y/n)? "
99 89
        if [ $? -eq 0 ]; then
100
            register_comp_serv $component
90
            register_component $component 1
101 91
        fi
102 92
    fi
103 93
}
b/snf-deploy/fabfile.py
600 600
def astakos_register_components():
601 601
    debug(env.host, " * Register services in astakos...")
602 602

  
603
    cyclades_base_url = "https://%s/cyclades/" % env.env.cyclades.fqdn
604
    pithos_base_url = "https://%s/pithos/" % env.env.pithos.fqdn
605
    astakos_base_url = "https://%s/astakos/" % env.env.accounts.fqdn
603
    cyclades_base_url = "https://%s/cyclades" % env.env.cyclades.fqdn
604
    pithos_base_url = "https://%s/pithos" % env.env.pithos.fqdn
605
    astakos_base_url = "https://%s/astakos" % env.env.accounts.fqdn
606 606

  
607 607
    cmd = """
608
    snf-manage component-add "home" https://{0} home-icon.png
609
    snf-manage component-add "cyclades" {1}ui/
610
    snf-manage component-add "pithos" {2}ui/
611
    snf-manage component-add "astakos" {3}ui/
608
    snf-manage component-add "home" --ui-url https://{0}
609
    snf-manage component-add "cyclades" --base-url {1} --ui-url {1}/ui
610
    snf-manage component-add "pithos" --base-url {2} --ui-url {2}/ui
611
    snf-manage component-add "astakos" --base-url {3} --ui-url {3}/ui
612 612
    """.format(env.env.cms.fqdn, cyclades_base_url,
613 613
               pithos_base_url, astakos_base_url)
614 614
    try_run(cmd)

Also available in: Unified diff