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 21:49:42 +0100

I ran ports and instance for these new changes. If it looks ok I'll
check it in. Attached are the source.
Running cluster now.

Index: src/main/java/com/sun/enterprise/config/serverbeans/ServerHelper.java
===================================================================
---
src/main/java/com/sun/enterprise/config/serverbeans/ServerHelper.java
(revision 39006)
+++
src/main/java/com/sun/enterprise/config/serverbeans/ServerHelper.java
(working copy)
@@ -52,9 +52,9 @@
  *
  * @author Byron Nevins
  */
-class ServerHelper {
+public class ServerHelper {
 
- ServerHelper(Server theServer, Config theConfig) {
+ public ServerHelper(Server theServer, Config theConfig) {
         server = theServer;
         config = theConfig;
 
@@ -84,13 +84,17 @@
     }
 
      String getHost() {
- String hostName = null;
         Dom serverDom = Dom.unwrap(server);
         Nodes nodes = serverDom.getHabitat().getComponent(Nodes.class);
         if (server == null || nodes == null) {
             return null;
         }
 
+ return getHost(nodes);
+ }
+
+ public String getHost(Nodes nodes) {
+ String hostName = null;
         // Get it from the node associated with the server
         String nodeName = server.getNode();
         if (StringUtils.ok(nodeName)) {

Index: src/main/java/com/sun/enterprise/config/util/PortManager.java
===================================================================
--- src/main/java/com/sun/enterprise/config/util/PortManager.java
(revision 39006)
+++ src/main/java/com/sun/enterprise/config/util/PortManager.java
(working copy)
@@ -39,6 +39,7 @@
 import com.sun.enterprise.config.serverbeans.Config;
 import com.sun.enterprise.config.serverbeans.Domain;
 import com.sun.enterprise.config.serverbeans.Server;
+import com.sun.enterprise.config.serverbeans.ServerHelper;
 import com.sun.enterprise.config.serverbeans.SystemProperty;
 import com.sun.enterprise.util.ObjectAnalyzer;
 import com.sun.enterprise.util.StringUtils;
@@ -62,8 +63,9 @@
 
             newServer = theNewServer;
             domain = theDomain;
+ ServerHelper helper = new ServerHelper(newServer, config);
             serverName = newServer.getName();
- host = newServer.getHost();
+ host = helper.getHost(domain.getNodes());
             allPorts = new ArrayList<Integer>();
             newServerPorts = new ServerPorts(cluster, config, domain,
newServer);



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




/*
 * 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.Server;
import com.sun.enterprise.config.serverbeans.ServerHelper;
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;
            ServerHelper helper = new ServerHelper(newServer, config);
            serverName = newServer.getName();
            host = helper.getHost(domain.getNodes());
            allPorts = new ArrayList<Integer>();
            newServerPorts = new ServerPorts(cluster, config, domain, newServer);

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

            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 final String host;
    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;
}


/*
 * 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.serverbeans;

import com.sun.enterprise.config.serverbeans.*;
import com.sun.enterprise.config.serverbeans.Server;
import com.sun.enterprise.util.StringUtils;
import com.sun.enterprise.util.net.NetUtils;
import com.sun.grizzly.config.dom.NetworkListener;
import java.util.List;
import org.glassfish.config.support.GlassFishConfigBean;
import org.glassfish.config.support.PropertyResolver;
import org.jvnet.hk2.config.Dom;

/**
 * The Server.java file is getting pretty bloated.
 * Offload some utilities here.
 * Nothing in here is visible outside this package...
 *
 * @author Byron Nevins
 */
public class ServerHelper {

    public ServerHelper(Server theServer, Config theConfig) {
        server = theServer;
        config = theConfig;

        if(server == null || config == null)
            throw new IllegalArgumentException();
    }

    int getAdminPort() {
        try {
            if (server == null)
                return -1;

            if (config == null)
                return -1;

            String portString = getAdminPortString(server, config);

            if (portString == null)
                return -1; // get out quick. it is kosher to call with a null Server

            return Integer.parseInt(portString);
        }
        catch (Exception e) {
            // drop through...
        }
        return -1;
    }

     String getHost() {
        Dom serverDom = Dom.unwrap(server);
        Nodes nodes = serverDom.getHabitat().getComponent(Nodes.class);
        if (server == null || nodes == null) {
            return null;
        }

        return getHost(nodes);
    }

     public String getHost(Nodes nodes) {
        String hostName = null;
        // Get it from the node associated with the server
        String nodeName = server.getNode();
        if (StringUtils.ok(nodeName)) {
            Node node = nodes.getNode(nodeName);
            if (node != null) {
                hostName = node.getNodeHost();
            }
            // XXX Hack to get around the fact that the default localhost
            // node entry is malformed
            if (hostName == null && nodeName.equals("localhost")) {
                hostName = "localhost";
            }
        }

        if (StringUtils.ok(hostName)) {
            return hostName;
        }
        else {
            return null;
        }
    }

     // very simple generic check
     boolean isRunning() {
        try {
            return NetUtils.isRunning(getHost(), getAdminPort());
        }
        catch(Exception e) {
            // fall through
        }
         return false;
     }

    ///////////////////////////////////////////
    /////////////////// all private below
    ///////////////////////////////////////////
    private String getAdminPortString(Server server, Config config) {
        if (server == null || config == null)
            return null;

        try {
            List<NetworkListener> listeners = config.getNetworkConfig().getNetworkListeners().getNetworkListener();

            for (NetworkListener listener : listeners) {
                if ("admin-listener".equals(listener.getProtocol()))
                    return translatePort(listener, server, config);
            }
        }
        catch (Exception e) {
            // handled below...
        }
        return null;
    }

    private String translatePort(NetworkListener adminListener, Server server, Config config) {
        NetworkListener adminListenerRaw = null;

        try {
            Dom serverDom = Dom.unwrap(server);
            Domain domain = serverDom.getHabitat().getComponent(Domain.class);

            adminListenerRaw = GlassFishConfigBean.getRawView(adminListener);
            String portString = adminListenerRaw.getPort();

            if (!isToken(portString))
                return portString;

            PropertyResolver resolver = new PropertyResolver(domain, server.getName());
            return resolver.getPropertyValue(portString);
        }
        catch (ClassCastException e) {
            //jc: workaround for issue 12354
            // TODO severe error
            return translatePortOld(adminListener.getPort(), server, config);
        }
    }

    private String translatePortOld(String portString, Server server, Config config) {
        if (!isToken(portString))
            return portString;

        // isToken returned true so we are NOT assuming anything below!
        String key = portString.substring(2, portString.length() - 1);

        // check cluster and the cluster's config if applicable
        // bnevins Jul 18, 2010 -- don't botehr this should never be called anymore
        SystemProperty prop = server.getSystemProperty(key);

        if (prop != null) {
            return prop.getValue();
        }

        prop = config.getSystemProperty(key);

        if (prop != null) {
            return prop.getValue();
        }

        return null;
    }

    private static boolean isToken(String s) {
        return s != null
                && s.startsWith("${")
                && s.endsWith("}")
                && s.length() > 3;
    }
    private final Server server;
    private final Config config;
}