Revision 0ff9b312

b/kamaki/cli/commands/snf-astakos.py
31 31
# interpreted as representing official policies, either expressed
32 32
# or implied, of GRNET S.A.command
33 33

  
34
from json import loads
34
from json import loads, load
35
from sys import stdin
36
from os.path import abspath
35 37

  
36 38
from astakosclient import AstakosClient, AstakosClientException
37 39

  
......
46 48
from kamaki.cli.logger import get_logger
47 49

  
48 50
snfastakos_cmds = CommandTree('astakos', 'astakosclient CLI')
49
_commands = [snfastakos_cmds]
51
snfproject_cmds = CommandTree('project', 'Synnefo project management CLI')
52
_commands = [snfastakos_cmds, snfproject_cmds]
50 53

  
51 54

  
52 55
def astakoserror(foo):
......
477 480
# XXX issue_commission, issue_one_commission
478 481

  
479 482

  
480
@command(snfastakos_cmds)
481
class astakos_test(_astakos_init):
482
    """Test an astakos command"""
483
# Project commands
484

  
485

  
486
_project_specs = """
487
    {
488
        "name": name,
489
        "owner": uuid,
490
        "homepage": homepage,         # optional
491
        "description": description,   # optional
492
        "comments": comments,         # optional
493
        "start_date": date,           # optional
494
        "end_date": date,
495
        "join_policy": "auto" | "moderated" | "closed",  # default: "moderated"
496
        "leave_policy": "auto" | "moderated" | "closed", # default: "auto"
497
        "resources": {
498
            "cyclades.vm": {
499
                "project_capacity": int or null,
500
                 "member_capacity": int
501
            }
502
        }
503
  }
504
  """
505

  
506

  
507
def apply_notification(foo):
508
    def wrap(self, *args, **kwargs):
509
        r = foo(self, *args, **kwargs)
510
        print 'Application is submitted successfully'
511
        return r
512
    return wrap
513

  
514

  
515
@command(snfproject_cmds)
516
class project_list(_astakos_init, _optional_json):
517
    """List all projects"""
518

  
519
    arguments = dict(
520
        name=ValueArgument('Filter by name', ('--with-name', )),
521
        state=ValueArgument('Filter by state', ('--with-state', )),
522
        owner=ValueArgument('Filter by owner', ('--with-owner', ))
523
    )
524

  
525
    @errors.generic.all
526
    @astakoserror
527
    def _run(self):
528
        self._print(self.client.get_projects(
529
            self.token, self['name'], self['state'], self['owner']))
530

  
531
    def main(self):
532
        super(self.__class__, self)._run()
533
        self._run()
534

  
535

  
536
@command(snfproject_cmds)
537
class project_info(_astakos_init, _optional_json):
538
    """Get details for a project"""
539

  
540
    @errors.generic.all
541
    @astakoserror
542
    def _run(self, project_id):
543
        self._print(
544
            self.client.get_projects(self.token, project_id), print_dict)
545

  
546
    def main(self, project_id):
547
        super(self.__class__, self)._run()
548
        self._run(project_id)
549

  
550

  
551
@command(snfproject_cmds)
552
class project_create(_astakos_init, _optional_json):
553
    """Apply for a new project (input a json-dict)
554
    Project details must be provided as a json-formated dict from the standard
555
    input, or through a file
556
    """
557

  
558
    __doc__ += _project_specs
559

  
560
    arguments = dict(
561
        specs_path=ValueArgument(
562
            'Specification file path (content must be in json)', '--spec-file')
563
    )
564

  
565
    @errors.generic.all
566
    @astakoserror
567
    @apply_notification
568
    def _run(self):
569
        input_stream = open(abspath(self['specs_path'])) if (
570
            self['specs_path']) else stdin
571
        specs = load(input_stream)
572
        self._print(self.client.create_project(self.token, specs), print_dict)
573

  
574
    def main(self):
575
        super(self.__class__, self)._run()
576
        self._run()
577

  
578

  
579
@command(snfproject_cmds)
580
class project_modify(_astakos_init, _optional_json):
581
    """Modify a project (input a json-dict)
582
    Project details must be provided as a json-formated dict from the standard
583
    input, or through a file
584
    """
585

  
586
    __doc__ += _project_specs
587

  
588
    arguments = dict(
589
        specs_path=ValueArgument(
590
            'Specification file path (content must be in json)', '--spec-file')
591
    )
592

  
593
    @errors.generic.all
594
    @astakoserror
595
    @apply_notification
596
    def _run(self, project_id):
597
        input_stream = open(abspath(self['specs_path'])) if (
598
            self['specs_path']) else stdin
599
        specs = load(input_stream)
600
        self._print(
601
            self.client.modify_project(self.token, project_id, specs),
602
            print_dict)
603

  
604
    def main(self, project_id):
605
        super(self.__class__, self)._run()
606
        self._run(project_id)
607

  
608

  
609
class _project_action(_astakos_init):
610

  
611
    action = ''
612

  
613
    @errors.generic.all
614
    @astakoserror
615
    @apply_notification
616
    def _run(self, project_id, quote_a_reason):
617
        self.client.project_action(
618
            self.token, project_id, self.action, quote_a_reason)
619

  
620
    def main(self, project_id, quote_a_reason=''):
621
        super(_project_action, self)._run()
622
        self._run(project_id, quote_a_reason)
623

  
624

  
625
@command(snfproject_cmds)
626
class project_suspend(_project_action):
627
    """Apply for a project suspension"""
628
    action = 'suspend'
629

  
630

  
631
@command(snfproject_cmds)
632
class project_unsuspend(_project_action):
633
    """Apply for a project un-suspension"""
634
    action = 'unsuspend'
635

  
636

  
637
@command(snfproject_cmds)
638
class project_terminate(_project_action):
639
    """Apply for a project termination"""
640
    action = 'terminate'
641

  
642

  
643
@command(snfproject_cmds)
644
class project_reinstate(_project_action):
645
    """Apply for a project reinstatement"""
646
    action = 'reinstate'
647

  
648

  
649
@command(snfproject_cmds)
650
class project_application(_project_action):
651
    """Application management commands"""
652

  
653

  
654
@command(snfproject_cmds)
655
class project_application_list(_astakos_init, _optional_json):
656
    """List all applications (old and new)"""
657

  
658
    arguments = dict(
659
        project=ValueArgument('Filter by project id', '--with-project-id')
660
    )
661

  
662
    @errors.generic.all
663
    @astakoserror
664
    def _run(self):
665
        self._print(self.client.get_applications(self.token, self['project']))
666

  
667
    def main(self):
668
        super(self.__class__, self)._run()
669
        self._run()
670

  
671

  
672
@command(snfproject_cmds)
673
class project_application_info(_astakos_init, _optional_json):
674
    """Get details on an application"""
675

  
676
    @errors.generic.all
677
    @astakoserror
678
    def _run(self, app_id):
679
        self._print(
680
            self.client.get_application(self.token, app_id), print_dict)
681

  
682
    def main(self, application_id):
683
        super(self.__class__, self)._run()
684
        self._run(application_id)
685

  
686

  
687
class _application_action(_astakos_init):
688

  
689
    action = ''
690

  
691
    @errors.generic.all
692
    @astakoserror
693
    def _run(self, app_id, quote_a_reason):
694
        self.client.application_action(
695
            self.token, app_id, self.action, quote_a_reason)
696

  
697
    def main(self, application_id, quote_a_reason=''):
698
        super(_application_action, self)._run()
699
        self._run(application_id, quote_a_reason)
700

  
701

  
702
@command(snfproject_cmds)
703
class project_application_approve(_application_action):
704
    """Approve an application (special privileges needed)"""
705
    action = 'approve'
706

  
707

  
708
@command(snfproject_cmds)
709
class project_application_deny(_application_action):
710
    """Deny an application (special privileges needed)"""
711
    action = 'deny'
712

  
713

  
714
@command(snfproject_cmds)
715
class project_application_dismiss(_application_action):
716
    """Dismiss your denied application"""
717
    action = 'dismiss'
718

  
719

  
720
@command(snfproject_cmds)
721
class project_application_cancel(_application_action):
722
    """Cancel your application"""
723
    action = 'cancel'
724

  
725

  
726
@command(snfproject_cmds)
727
class project_membership(_astakos_init):
728
    """Project membership management commands"""
729

  
730

  
731
@command(snfproject_cmds)
732
class project_membership_list(_astakos_init, _optional_json):
733
    """List all memberships"""
734

  
735
    arguments = dict(
736
        project=ValueArgument('Filter by project id', '--with-project-id')
737
    )
738

  
739
    @errors.generic.all
740
    @astakoserror
741
    def _run(self):
742
        self._print(self.client.get_memberships(self['project']))
743

  
744
    def main(self):
745
        super(self.__class__, self)._run()
746
        self._run()
747

  
748

  
749
@command(snfproject_cmds)
750
class project_membership_info(_astakos_init, _optional_json):
751
    """Details on a membership"""
483 752

  
484 753
    @errors.generic.all
485 754
    @astakoserror
486
    def _run(self, *args):
487
        r = self.client.get_pending_commissions(self.token)
488
        print r
755
    def _run(self, memb_id):
756
        self._print(self.client.get_membership(memb_id), print_dict)
489 757

  
490
    def main(self, *args):
758
    def main(self, membership_id):
491 759
        super(self.__class__, self)._run()
492
        self._run(*args)
760
        self._run(membership_id)
761

  
762

  
763
class _membership_action(_astakos_init, _optional_json):
764

  
765
    action = ''
766

  
767
    @errors.generic.all
768
    @astakoserror
769
    def _run(self, memb_id, quote_a_reason):
770
        self._print(
771
            self.client.membership_action(
772
                self.token, memb_id, self.action, quote_a_reason),
773
            print_dict)
774

  
775
    def main(self, membership_id, quote_a_reason=''):
776
        super(_membership_action, self)._run()
777
        self._run(membership_id, quote_a_reason)
778

  
779

  
780
@command(snfproject_cmds)
781
class project_membership_leave(_membership_action):
782
    """Leave a project you have membership to"""
783
    action = 'leave'
784

  
785

  
786
@command(snfproject_cmds)
787
class project_membership_cancel(_membership_action):
788
    """Cancel your (probably pending) membership to a project"""
789
    action = 'cancel'
790

  
791

  
792
@command(snfproject_cmds)
793
class project_membership_accept(_membership_action):
794
    """Accept a membership for a project you manage"""
795
    action = 'accept'
796

  
797

  
798
@command(snfproject_cmds)
799
class project_membership_reject(_membership_action):
800
    """Reject a membership for project you manage"""
801
    action = 'reject'
802

  
803

  
804
@command(snfproject_cmds)
805
class project_membership_remove(_membership_action):
806
    """Remove a membership for a project you manage"""
807
    action = 'remove'
808

  
809

  
810
@command(snfproject_cmds)
811
class project_membership_join(_astakos_init):
812
    """Get a membership to a project"""
813

  
814
    @errors.generic.all
815
    @astakoserror
816
    def _run(self, project_id):
817
        print self.client.join_project(self.token, project_id)
818

  
819
    def main(self, project_id):
820
        super(_membership_action, self)._run()
821
        self._run(project_id)
822

  
823

  
824
@command(snfproject_cmds)
825
class project_membership_enroll(_astakos_init):
826
    """Enroll somebody to a project you manage"""
827

  
828
    @errors.generic.all
829
    @astakoserror
830
    def _run(self, project_id, email):
831
        print self.client.enroll_member(self.token, project_id, email)
832

  
833
    def main(self, project_id, email):
834
        super(_membership_action, self)._run()
835
        self._run(project_id, email)

Also available in: Unified diff