admin@glassfish.java.net

Re: create-local-instance fails in deployment devtests; admin hudson jobs are failing

From: Jennifer Chou <jennifer.chou_at_oracle.com>
Date: Fri, 23 Jul 2010 20:49:37 +0100

You can test with this PortManager (admin\config-api)

On 7/23/2010 8:34 PM, Tim Quinn wrote:
> I see there is frequent mail traffic on this, which is reassuring!
>
> Is there an ETA for the fix? I have some unrelated changes but I need
> to run deployment cluster devtests before checking in my changes, and
> those tests don't work due (I think) to this problem.
>
> Just trying to plan my work...
>
> Thanks.
>
> - Tim
>
> On Jul 23, 2010, at 1:55 PM, Jennifer Chou wrote:
>
>> You mean the patch below? I ran the ports, instance, and cluster
>> devtests.
>>
>> On 7/23/2010 7:45 PM, Byron Nevins wrote:
>>> Can you try it on devtests and see if it works?
>>>
>>>
>>> On 7/23/2010 11:42 AM, Jennifer Chou wrote:
>>>> ok sounds good. not checking anything in.
>>>>
>>>> On 7/23/2010 7:32 PM, Byron Nevins wrote:
>>>>> I recommend NOT doing this. We should have this ugly code in one
>>>>> and only one place. ServerHelper has those lines now. It just
>>>>> needs to be refactored into another method in ServerHelper where
>>>>> you call it with a Nodes or Node object...
>>>>>
>>>>>
>>>>> On 7/23/2010 10:44 AM, Jennifer Chou wrote:
>>>>>> Here's the patch I was going to checkin. just running ql on it
>>>>>> right now. Let me know if you want me to go ahead with checking in.
>>>>>> I was thinking that since server being created as passed to
>>>>>> PortManager. Then port manager calls the getHost duck typed
>>>>>> method on Server which I think may not have that info yet?
>>>>>> So I removed call to duck typed method server.getHost in PortManager.
>>>>>>
>>>>>> Index: src/main/java/com/sun/enterprise/config/util/PortManager.java
>>>>>> ===================================================================
>>>>>> ---
>>>>>> src/main/java/com/sun/enterprise/config/util/PortManager.java
>>>>>> (revisio
>>>>>> n 39006)
>>>>>> +++
>>>>>> src/main/java/com/sun/enterprise/config/util/PortManager.java
>>>>>> (working
>>>>>> copy)
>>>>>> @@ -38,6 +38,7 @@
>>>>>> import com.sun.enterprise.config.serverbeans.Cluster;
>>>>>> import com.sun.enterprise.config.serverbeans.Config;
>>>>>> import com.sun.enterprise.config.serverbeans.Domain;
>>>>>> +import com.sun.enterprise.config.serverbeans.Node;
>>>>>> import com.sun.enterprise.config.serverbeans.Server;
>>>>>> import com.sun.enterprise.config.serverbeans.SystemProperty;
>>>>>> import com.sun.enterprise.util.ObjectAnalyzer;
>>>>>> @@ -63,12 +64,26 @@
>>>>>> newServer = theNewServer;
>>>>>> domain = theDomain;
>>>>>> serverName = newServer.getName();
>>>>>> - host = newServer.getHost();
>>>>>> + String nodeName = newServer.getNode();
>>>>>> + if (!StringUtils.ok(nodeName))
>>>>>> + throw new
>>>>>> TransactionFailure(Strings.get("PortManager.noNodeSpecified",
>>>>>> serverName));
>>>>>> +
>>>>>> + Node node = domain.getNodeNamed(nodeName);
>>>>>> + if (node == null)
>>>>>> + throw new
>>>>>> TransactionFailure(Strings.get("PortManager.noNode",nodeName));
>>>>>> +
>>>>>> + host = node.getNodeHost();
>>>>>> + // XXX Hack to get around the fact that the default
>>>>>> localhost
>>>>>> + // node entry is malformed
>>>>>> + if (host == null && nodeName.equals("localhost")) {
>>>>>> + host = "localhost";
>>>>>> + }
>>>>>> +
>>>>>> allPorts = new ArrayList<Integer>();
>>>>>> newServerPorts = new ServerPorts(cluster, config,
>>>>>> domain, newServer);
>>>>>>
>>>>>> if (!StringUtils.ok(host))
>>>>>> - throw new
>>>>>> TransactionFailure(Strings.get("PortManager.noHost",serverName));
>>>>>> + throw new
>>>>>> TransactionFailure(Strings.get("PortManager.noHost",nodeName));
>>>>>>
>>>>>> isLocal = NetUtils.IsThisHostLocal(host);
>>>>>>
>>>>>> @@ -249,7 +264,7 @@
>>>>>> private final Server newServer;
>>>>>> private final boolean isLocal;
>>>>>> private final Domain domain;
>>>>>> - private final String host;
>>>>>> + private String host = null;
>>>>>> private final List<Integer> allPorts;
>>>>>> private final List<Server> allServers;
>>>>>> private final List<ServerPorts> serversOnHost;
>>>>>>
>>>>>> Index:
>>>>>> src/main/java/com/sun/enterprise/config/util/LocalStrings.properties
>>>>>> ===================================================================
>>>>>> ---
>>>>>> src/main/java/com/sun/enterprise/config/util/LocalStrings.properties
>>>>>> (revision 39006)
>>>>>> +++
>>>>>> src/main/java/com/sun/enterprise/config/util/LocalStrings.properties
>>>>>> (working copy)
>>>>>> @@ -3,7 +3,9 @@
>>>>>> PortUtils.duplicate_port=Found two system-property elements with
>>>>>> the same port
>>>>>> number ({0}) for {1}.
>>>>>> PortUtils.non_int_port=Found a system-property with a
>>>>>> non-integer port number (
>>>>>> {0}) for {1}.
>>>>>> PortUtils.illegal_port_number=The supplied port number, {0}, for
>>>>>> the server, {1
>>>>>> }, is illegal. Legal values are 0 to {2} inclusive.
>>>>>> -PortManager.noHost=There is no node-agent-ref specified for the
>>>>>> instance {0}.
>>>>>> +PortManager.noNodeSpecified=There is no node specified for the
>>>>>> instance {0}.
>>>>>> +PortManager.noNode=Node {0} does not exist.
>>>>>> +PortManager.noHost=Node host is not specified on node {0}.
>>>>>> PortManager.noFreePort=Can''t locate a free port. None of the
>>>>>> ports between {0
>>>>>> } and {1} are available.
>>>>>>
>>>>>> On 7/23/2010 6:35 PM, Byron Nevins wrote:
>>>>>>> I just changed things last night -- I'll take a look.
>>>>>>>
>>>>>>> Jennifer -- Server.getHostName() on DAS returns null!!! I'll
>>>>>>> fix it...
>>>>>>>
>>>>>>> On 7/23/2010 9:49 AM, Jennifer Chou wrote:
>>>>>>>> working on fix right now.
>>>>>>>>
>>>>>>>> On 7/23/2010 5:39 PM, Tom Mueller wrote:
>>>>>>>>> Yes.
>>>>>>>>> Tom
>>>>>>>>>
>>>>>>>>> On 7/23/2010 11:37 AM, Tim Quinn wrote:
>>>>>>>>>> Hi.
>>>>>>>>>>
>>>>>>>>>> The Hudson admin job is red with (among other things) this
>>>>>>>>>> error when trying to create an instance:
>>>>>>>>>>
>>>>>>>>>> [java] remote failure: Exception while adding the new configuration org.jvnet.hk2.config.TransactionFailure: There is no node-agent-ref specified for the instance in_892228. : org.jvnet.hk2.config.TransactionFailure: There is no node-agent-ref specified for the instance in_892228.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> We are seeing the same error in the deployment devtests in
>>>>>>>>>> trying to create an instance.
>>>>>>>>>> Is someone looking into this?
>>>>>>>>>> - Tim
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>> --
>>>>> Byron Nevins - Oracle Corporation
>>>>> Home: 650-359-1290
>>>>> Cell: 650-784-4123
>>>>> Sierra: 209-295-2188
>>>>>
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: admin-unsubscribe_at_glassfish.dev.java.net
>>>>> For additional commands, e-mail: admin-help_at_glassfish.dev.java.net
>>>>
>>>
>>> --
>>> Byron Nevins - Oracle Corporation
>>> Home: 650-359-1290
>>> Cell: 650-784-4123
>>> Sierra: 209-295-2188
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: admin-unsubscribe_at_glassfish.dev.java.net For
>>> additional commands, e-mail: admin-help_at_glassfish.dev.java.net
>>
>
>
>
> Oracle <http://www.oracle.com>
> Tim Quinn | Principal Member of Technical Staff | +1.847.604.9475
> Oracle GlassFish Engineering
> Lake Forest, IL
>




/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License"). You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code. If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 *
 * Contributor(s):
 *
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license." If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above. However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
package com.sun.enterprise.config.util;

import com.sun.enterprise.config.serverbeans.Cluster;
import com.sun.enterprise.config.serverbeans.Config;
import com.sun.enterprise.config.serverbeans.Domain;
import com.sun.enterprise.config.serverbeans.Node;
import com.sun.enterprise.config.serverbeans.Server;
import com.sun.enterprise.config.serverbeans.SystemProperty;
import com.sun.enterprise.util.ObjectAnalyzer;
import com.sun.enterprise.util.StringUtils;
import com.sun.enterprise.util.Utility;
import com.sun.enterprise.util.net.*;
import java.beans.PropertyVetoException;
import java.util.*;
import org.jvnet.hk2.config.TransactionFailure;

/**
 * Hiding place for the remarkably complex logic of assigning ports to instances
 * GUARANTEE -- the only thing thrown from here is TransactionFailure
 * @author Byron Nevins
 */
public final class PortManager {

    public PortManager(Cluster cluster, Config config, Domain theDomain, Server theNewServer) throws TransactionFailure {
        try {
            if (theNewServer == null || theDomain == null)
                throw new TransactionFailure(Strings.get("internal.error", "null argument in PortManager constructor"));

            newServer = theNewServer;
            domain = theDomain;
            serverName = newServer.getName();
            String nodeName = newServer.getNode();
            if (!StringUtils.ok(nodeName))
                throw new TransactionFailure(Strings.get("PortManager.noNodeSpecified", serverName));
            
            Node node = domain.getNodeNamed(nodeName);
            if (node == null)
                throw new TransactionFailure(Strings.get("PortManager.noNode", nodeName));

            host = node.getNodeHost();
            // XXX Hack to get around the fact that the default localhost
            // node entry is malformed
            if (host == null && nodeName.equals("localhost")) {
                host = "localhost";
            }

            allPorts = new ArrayList<Integer>();
            newServerPorts = new ServerPorts(cluster, config, domain, newServer);

            if (!StringUtils.ok(host))
                throw new TransactionFailure(Strings.get("PortManager.noHost", nodeName));

            isLocal = NetUtils.IsThisHostLocal(host);


            allServers = domain.getServers().getServer();

            // why all this nonsense? ConcurrentModificationException!!!
            for (Iterator<Server> it = allServers.iterator(); it.hasNext();) {
                Server curr = it.next();
                if (serverName.equals(curr.getName())) {
                    it.remove();
                }
            }
            serversOnHost = new ArrayList<ServerPorts>();
        }
        catch (TransactionFailure tf) {
            throw tf;
        }
        catch (Exception e) {
            // this Exception will not take just a Throwable. I MUST give a string
            throw new TransactionFailure(e.toString(), e);
        }
    }

    public void process() throws TransactionFailure {
        try {
            // if there are no port system-property's -- no point in going on!
            if (newServerPorts.getMap().isEmpty())
                return; // all done!

            // make sure user-supplied props are not flaky
            PortUtils.checkInternalConsistency(newServer);

            // create a list of ALL servers running on the same machine
            createServerList();

            // create a sorted list of every port on every other server on the same machine.
            createAllPortsList();

            // we have a list of all possible conflicting server ports.
            // let's find some unused ports and reassign the variables inside
            // the ServerPorts class
            Map<String, Integer> reassigned = reassignPorts();
            Set<Map.Entry<String, Integer>> entries = reassigned.entrySet();


            List<SystemProperty> sps = newServer.getSystemProperty();

            for (Map.Entry<String, Integer> entry : entries) {
                String name = entry.getKey();
                int port = entry.getValue();
                changeSystemProperty(sps, name, "" + port); // do not want commas in the int!
            }
        }
        catch (Exception e) {
            throw new TransactionFailure(e.toString(), e);
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("PortManager Dump:");

        for (ServerPorts sp : serversOnHost)
            sb.append(sp).append('\n');

        sb.append("All Ports in all other servers on same host: " + allPorts);
        return sb.toString();
    }

    private void createServerList() {
        if (isLocal)
            createLocalServerList();
        else
            createRemoteServerList();

    }

    private void createLocalServerList() {
        for (Server server : allServers) {
            if (server.isDas())
                serversOnHost.add(new ServerPorts(domain, server));
            else if (NetUtils.IsThisHostLocal(server.getNode()))
                serversOnHost.add(new ServerPorts(domain, server));
        }
    }

    private void createRemoteServerList() {
        for (Server server : allServers) {
            // no DAS!
            if (server.isInstance() && sameHost(server))
                serversOnHost.add(new ServerPorts(domain, server));
        }
    }

    private boolean sameHost(Server server) {
        return NetUtils.isEqual(server.getNode(), host);
    }

    private Map<String, Integer> reassignPorts() throws TransactionFailure {
        // inefficient, probably a slicker way to do it. Not worth the effort
        // there are at most 8 items...

        Map<String, Integer> portProps = newServerPorts.getMap();
        Map<String, Integer> changedPortProps = new HashMap<String, Integer>();
        Set<Map.Entry<String, Integer>> entries = portProps.entrySet();

        for (Map.Entry<String, Integer> entry : entries) {
            String name = entry.getKey();
            Integer num = entry.getValue();
            Integer newNum = reassignPort(num);

            if (!newNum.equals(num))
                changedPortProps.put(name, newNum);
        }
        return changedPortProps;
    }

    private Integer reassignPort(Integer num) throws TransactionFailure {
        int max = num + 100;

        while (num < max) {
            num = getNextUnassignedPort(num);

            if (isPortFree(num))
                return num;
            else
                ++num;
        }
        throw new TransactionFailure(Strings.get("PortManager.noFreePort"));
    }

    private Integer getNextUnassignedPort(Integer num) throws TransactionFailure {
        int max = num + MAX_PORT_TRIES; // to avoid infinite loop

        for (int inum = num; inum < max; inum++) {
            if (!allPorts.contains(inum))
                return inum;
        }
        throw new TransactionFailure(Strings.get("PortManager.noFreePort", num, max));
    }

    private void changeSystemProperty(List<SystemProperty> sps, String name, String port) throws PropertyVetoException, TransactionFailure {
        for (SystemProperty sp : sps) {
            if (name.equals(sp.getName())) {
                sp.setValue(port);
                return;
            }
        }
        // does not exist -- let's add one!
        SystemProperty sp = newServer.createChild(SystemProperty.class);
        sp.setName(name);
        sp.setValue(port);
        sps.add(sp);
    }

    private boolean isPortFree(int num) {
        if (isLocal)
            return NetUtils.isPortFree(num);

        return NetUtils.isPortFree(host, num);
    }

    private void createAllPortsList() {

        for (ServerPorts sp : serversOnHost) {
            Collection<Integer> ii = sp.getMap().values();

            // do not want duplicates!!
            for (Integer i : ii)
                if (!allPorts.contains(i))
                    allPorts.add(i);
        }

        Collections.sort(allPorts);
    }
    private final String serverName;
    private final Server newServer;
    private final boolean isLocal;
    private final Domain domain;
    private String host = null;
    private final List<Integer> allPorts;
    private final List<Server> allServers;
    private final List<ServerPorts> serversOnHost;
    private final ServerPorts newServerPorts;
    private final boolean checkLivePorts = true;
    private static final int MAX_PORT_TRIES = 1100;
}