aboutsummaryrefslogtreecommitdiffstats
path: root/docs/docs_5G_PNF_Software_Upgrade.rst
blob: 9c7e6e00ecf0d9d72b118e4b6fcebca09207f318 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
.. This work is licensed under a Creative Commons Attribution 4.0
   International License. http://creativecommons.org/licenses/by/4.0
   
.. _docs_5g_pnf_software_upgrade:

5G PNF Software Upgrade
----------------------------

Description
~~~~~~~~~~~
The 5G PNF Software upgrade use case shows how users/network operators can modify the software running on an existing PNF. This use case is one aspect of Software Management. This could be used to update the PNF software to a newer or older version of software.

The Casablanca 5G PNF Software Upgrade Use Case Wiki Page can be found here: https://wiki.onap.org/display/DW/5G+-+PNF+Software+Update

How to Use
~~~~~~~~~~
Upgrading PNF (instance) software requires the user/network operator to trigger the upgrade operation from the UI, e.g. VID or UUI. In Cacablanca, users need use ONAP Controllers GUI to trigger the LCM opeations, like pre-check, post-check and upgrade. After receiving the API requests, the ONAP controllers will communicate to the external controller(EC) through south-bound adaptors, which is Ansible in R3.

Note that, both APPC and SDNC in R3 supported Ansible. Taking SDNC and Prechecking as an example, the steps are as follows:

1) In ansible server container, prepare the ssh connection conditions to the external controller, both ssh key file and ansible inventory configuration;

2) In sdnc controller container, update the dg configuration file: lcm-dg.properties.
For example:
::
lcm.pnf.upgrade-pre-check.playbookname=ansible_huawei_precheck
lcm.pnf.upgrade-post-check.playbookname=ansible_huawei_postcheck
lcm.pnf.upgrade-software.playbookname=ansible_huawei_upgrade

3) Login controller UI, access the pre-check LCM operation and send request.
Post upgrade-pre-check with the following request body:
::
{
    "input": {
      "common-header": {
      "timestamp": "2018-10-10T09:40:04.244Z",
      "api-ver": "2.00",
      "originator-id": "664be3d2-6c12-4f4b-a3e7-c349acced203",
      "request-id":"664be3d2-6c12-4f4b-a3e7-c349acced203",
      "sub-request-id": "1",
      "flags": {
                    "force" : "TRUE",
                    "ttl" : 60000
             }
      },
      "action": "UpgradePreCheck",
      "action-identifiers": {
        "vnf-id":"5gDU0001"
      },
      "payload": "{\"pnf-flag\":\"true\", \"pnf-name\": \"5gDU0001\",\"pnfId\": \"5gDU0001\", \"ipaddress-v4-oam\": \"EC_IP_address\",\"oldSwVersion\": \"v1\", \"targetSwVersion\": \"v2\", \"ruleName\": \"r001\", \"Id\": \"10\", \"additionalData\":\"{}\"}"}}

4) The HTTP API response code 200 and LCM retured code 400 (See APPC return code design specification) indicate success, otherwise failed.

Test Status and Plans
~~~~~~~~~~~~~~~~~~~~~
To see information on the status of the test see: https://wiki.onap.org/display/DW/5G+-+PNF+Software+Update+Test+Status

Known Issues and Resolutions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
None
* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/**
 * ============LICENSE_START====================================================
 * org.onap.aaf
 * ===========================================================================
 * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
 * ===========================================================================
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ============LICENSE_END====================================================
 *
 */

package org.onap.aaf.auth.gui.pages;

import java.io.IOException;
import java.net.ConnectException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.onap.aaf.auth.env.AuthzEnv;
import org.onap.aaf.auth.env.AuthzTrans;
import org.onap.aaf.auth.gui.AAF_GUI;
import org.onap.aaf.auth.gui.BreadCrumbs;
import org.onap.aaf.auth.gui.Form;
import org.onap.aaf.auth.gui.NamedCode;
import org.onap.aaf.auth.gui.Page;
import org.onap.aaf.auth.gui.Table;
import org.onap.aaf.auth.gui.Table.Cells;
import org.onap.aaf.auth.gui.table.AbsCell;
import org.onap.aaf.auth.gui.table.ButtonCell;
import org.onap.aaf.auth.gui.table.RadioCell;
import org.onap.aaf.auth.gui.table.TableData;
import org.onap.aaf.auth.gui.table.TextCell;
import org.onap.aaf.auth.gui.table.TextToolTipCell;
import org.onap.aaf.auth.org.Organization;
import org.onap.aaf.auth.org.Organization.Identity;
import org.onap.aaf.auth.org.OrganizationFactory;
import org.onap.aaf.cadi.CadiException;
import org.onap.aaf.cadi.client.Future;
import org.onap.aaf.cadi.client.Rcli;
import org.onap.aaf.cadi.client.Retryable;
import org.onap.aaf.misc.env.APIException;
import org.onap.aaf.misc.env.Env;
import org.onap.aaf.misc.env.Slot;
import org.onap.aaf.misc.env.TimeTaken;
import org.onap.aaf.misc.xgen.Cache;
import org.onap.aaf.misc.xgen.DynamicCode;
import org.onap.aaf.misc.xgen.Mark;
import org.onap.aaf.misc.xgen.html.HTMLGen;

import aaf.v2_0.Approval;
import aaf.v2_0.Approvals;

public class ApprovalForm extends Page {
    // Package on purpose
    static final String NAME="Approvals";
    static final String HREF = "/gui/approve";
    static final String[] FIELDS = new String[] {"line[]","user","delegate_of","as_user"};
    
    
    public ApprovalForm(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException {
        super(gui.env,NAME,HREF, FIELDS,

            new BreadCrumbs(breadcrumbs),
            new NamedCode(false, "filterByUser") {
                @Override
                public void code(final Cache<HTMLGen> cache, final HTMLGen hgen) throws APIException, IOException {
                    cache.dynamic(hgen, new DynamicCode<HTMLGen, AAF_GUI, AuthzTrans>() {
                        @Override
                        public void code(final AAF_GUI gui, final AuthzTrans trans,    final Cache<HTMLGen> cache, final HTMLGen hgen)    throws APIException, IOException {
                            String user = trans.get(trans.env().slot(NAME+".user"),"");
                            hgen.incr("p", "class=userFilter")
                                .text("Filter by User:")
                                .tagOnly("input", "type=text", "value="+user, "id=userTextBox")
                                .tagOnly("input", "type=button", "onclick=userFilter('"+HREF+"');", "value=Go!")
                                .end();
                                }
                    });
                }
            },
            new Form(true,new Table<AAF_GUI,AuthzTrans>("Approval Requests", gui.env.newTransNoAvg(),new Model(gui.env),"class=stdform"))
                .preamble("The following requires your Approval to proceed in the AAF System.</p><p class=subtext>Hover on Name for Identity; If Deny is the only option, User is no longer valid."),
            new NamedCode(false, "selectAlljs") {
                @Override
                public void code(final Cache<HTMLGen> cache, final HTMLGen hgen) throws APIException, IOException {
                    Mark jsStart = new Mark();
                    hgen.js(jsStart);
                    hgen.text("function selectAll(radioClass) {");
                    hgen.text("var radios = document.querySelectorAll(\".\"+radioClass);");
                    hgen.text("for (i = 0; i < radios.length; i++) {");
                    hgen.text("radios[i].checked = true;");
                    hgen.text("}");
                    hgen.text("}");
                    hgen.end(jsStart);
                }
            });
    }
    
    /**
     * Implement the Table Content for Approvals
     * 
     * @author Jonathan
     *
     */
    private static class Model extends TableData<AAF_GUI,AuthzTrans> {
        //TODO come up with a generic way to do ILM Info (people page)
//        private static final String TODO_ILM_INFO = "TODO: ILM Info";
        
        
        private static final String[] headers = new String[] {"Identity","Request","Approve","Deny"};
        private Slot sUser;
        private Slot sAsDelegate;
        private Slot sAsUser;
        
        public Model(AuthzEnv env) {
            sUser = env.slot(NAME+".user");
            sAsDelegate = env.slot(NAME+".delegate_of");
            sAsUser = env.slot(NAME + ".as_user");
        }
        
        @Override
        public String[] headers() {
            return headers;
        }
        
        @Override
        public Cells get(final AuthzTrans trans, final AAF_GUI gui) {
            final String userParam = trans.get(sUser, null);
            
            final String asDelegate = trans.get(sAsDelegate, null);
            final String approver;
            if(asDelegate==null) {
                approver = trans.get(sAsUser,trans.user());
            } else {
                approver = asDelegate;
            }
             
            ArrayList<AbsCell[]> rv = new ArrayList<>();
            String msg = null;
            TimeTaken tt = trans.start("AAF Get Approvals for Approver",Env.REMOTE);
            try {
                final List<Approval> pendingApprovals = new ArrayList<>();
                final List<Integer> beginIndicesPerApprover = new ArrayList<>();
                int numLeft = gui.clientAsUser(trans.getUserPrincipal(), new Retryable<Integer>() {
                    @Override
                    public Integer code(Rcli<?> client) throws CadiException, ConnectException, APIException {
                        Future<Approvals> fa = client.read("/authz/approval/approver/"+approver,gui.getDF(Approvals.class));
                        int numLeft = 0;
                        if (fa.get(AAF_GUI.TIMEOUT)) {
                            
                            if (fa.value!=null) {
                                for (Approval appr : fa.value.getApprovals()) {
                                    if ("pending".equals(appr.getStatus())) {
                                        if (userParam!=null && !appr.getUser().equalsIgnoreCase(userParam)) {
                                                numLeft++;
                                                continue;
                                        }
                                        pendingApprovals.add(appr);
                                    }
                                }
                            }
                            
                            String prevApprover = null;
                            int overallIndex = 0;
                                
                            for (Approval appr : pendingApprovals) {
                                String currApprover = appr.getApprover();
                                if (!currApprover.equals(prevApprover)) {
                                    prevApprover = currApprover;
                                    beginIndicesPerApprover.add(overallIndex);
                                }
                                overallIndex++;
                            }
                        }
                        return numLeft;
                    }
                });
                
                if (!pendingApprovals.isEmpty()) {
                    // Only add select all links if we have approvals
                    AbsCell[] selectAllRow = new AbsCell[] {
                            AbsCell.Null,
                            AbsCell.Null,
                            new ButtonCell("all", "onclick=selectAll('approve')", "class=selectAllButton"),
                            new ButtonCell("all", "onclick=selectAll('deny')", "class=selectAllButton")
                        };
                    rv.add(selectAllRow);
                }
                        
                int line=-1;
                
                while (!beginIndicesPerApprover.isEmpty()) {
                    int beginIndex = beginIndicesPerApprover.remove(0);
                    int endIndex = (beginIndicesPerApprover.isEmpty()?pendingApprovals.size():beginIndicesPerApprover.get(0));
                    List<Approval> currApproverList = pendingApprovals.subList(beginIndex, endIndex);
                    
                    Identity iapprover = trans.org().getIdentity(trans,currApproverList.get(0).getApprover());
                    if(iapprover==null) {
                        rv.add(new AbsCell[] {
                                new TextCell(currApproverList.get(0).getApprover() + " is not part of Organization",
                                        new String[] {"colspan=4", "class=head"})
                        });
                    } else {
                        if (!iapprover.fullID().equals(trans.user())) {
                        
                            AbsCell[] approverHeader;
    //                        if (domainOfUser.equals(domainOfApprover)) {
    //                            approverHeader = new AbsCell[] { 
    //                                    new TextAndRefCell("Approvals Delegated to Me by ", currApproverFull,
    //                                            TODO_ILM_INFO + currApproverShort, 
    //                                            true,
    //                                            new String[] {"colspan=4", "class=head"})
    //                            };
    //                        } else {
                                approverHeader = new AbsCell[] { 
                                        new TextCell("Approvals Delegated to Me by " + iapprover.fullName() 
                                            + '(' + iapprover.id() + ')',
                                                new String[] {"colspan=4", "class=head"})
                                };
    //                        }
                            rv.add(approverHeader);
                        }
                        
                        // Sort by User Requesting
                        Collections.sort(currApproverList, new Comparator<Approval>() {
                            @Override
                            public int compare(Approval a1, Approval a2) {
                                return a1.getUser().compareTo(a2.getUser());
                            }
                        });
                        
                        String prevUser = null;
                        boolean userOK=true;
                        for (Approval appr : currApproverList) {
                            if (++line<MAX_LINE) { // limit number displayed at one time.
                                AbsCell userCell;
                                String user = appr.getUser();
                                
                                if (user.equals(prevUser)) {
                                    userCell = AbsCell.Null; 
                                } else if (user.endsWith(trans.org().getRealm())){
                                    userOK=true;
                                    String title;
                                    Organization org = OrganizationFactory.obtain(trans.env(), user);
                                    if (org==null) {
                                        title="";
                                        userCell = new TextCell(user);
                                    } else {
                                        Identity au = org.getIdentity(trans, user);
                                        if (au!=null) {
                                            if(au.isPerson()) {
                                                userCell = new TextToolTipCell(au.fullName(),"Identity: " + au.id());
                                            } else {
                                                Identity managedBy = au.responsibleTo();
                                                if (managedBy==null) {
                                                    title ="Identity: " + au.type();
                                                } else {
                                                    title="Sponsor: " + managedBy.fullName();                                                
                                                }
                                                userCell = new TextToolTipCell(au.fullID(),title);
                                            }
                                        } else {
                                            userOK=false;
                                            title="Not a User at " + org.getName();
                                            userCell = new TextToolTipCell(user,title);
                                        }
                                    }
    //                                userCell = new RefCell(prevUser,
    //                                    TODO_ILM_INFO+user.substring(0, user.length()-domainOfApprover.length()),
    //                                    true,
    //                                    title);
                                    
                                } else {
                                    userCell = new TextCell(user);
                                }
                                AbsCell[] sa = new AbsCell[] {
                                    userCell,
                                    new TextCell(appr.getMemo()),
                                    userOK?new RadioCell("line."+ line,"approve", "approved|"+appr.getTicket()):new TextCell(""),
                                    new RadioCell("line."+ line,"deny", "denied|"+appr.getTicket())
                                };
                                rv.add(sa);
                                prevUser=user;
                            } else {
                                ++numLeft;
                            }
                        }
                    }
                    if (numLeft>0) {
                        msg = "After these, there will be " + numLeft + " approvals left to process";
                    }
                    if (rv.isEmpty()) {
                        if (numLeft>0) {
                            msg = "No Approvals to process at this time for user " + userParam +". You have " 
                                + numLeft + " other approvals to process.";
                        } else {
                            msg = "No Approvals to process at this time";
                        }
                    }
                }
            } catch (Exception e) {
                trans.error().log(e);
            } finally {
                tt.done();
            }
        return new Cells(rv,msg);
        }
    }
}