404 returned when app/Add-on installation on newly published app as private listing

Hey guys,

So I have finally managed to upload my app to the atlassian marketplace (private listing). I was able to test this out in my local machine by following this steps here: https://developers.atlassian.com/cloud/jira/platform/build-a-jira-app-using-a-framework/

So I would like to test this out on a real installation through jira marketplace and kept getting a 404 error during installation: “The add-on host returned HTTP response code 404 when we tried to contact it during installation. Please try again later or contact the add-on vendor.” I installed this app by uploading the token url from the private listing app token page.

So I’m not sure what causes that error, I have followed the steps I found from Jira to configure the atlassian-connect.json, and everything link provided in the atlassian-connect.json seems to be valid.

Any help/ideas on how to resolve this would be much appreciated. I have also included my atlassian-connect.json link that is hosted in our company’s server to help me see what could be the issue that trigger the error.

https://wsna-cdn.azurewebsites.net/products/OneConnect/JIRA/OneConnect-Jira-ProjectOnline/atlassian-connect.json

Thanks

During the installation process, Jira calls out to the app to see if its able to be installed.
The REST API it uses is comprised with

installUrl = descriptor.baseUrl + descriptor.lifecycle.installed

This url is currently https://wsna-cdn.azurewebsites.net/installed
This REST API must return a 2XX response in order for the app to install.
You can read more about the lifecycle here

Thanks for the reply. I have seen that page before and knowing that the lifecycle property is relative to the base URL. However, I don’t get how it is supposed to return 2xx as you just mentioned?

The base url would be my hosting server url that I put my stuffs into, and followed that is the path, and how it is supposed to work with {{baseUrl}}/installed?

Maybe I misunderstood something, can you instead point me what could possibly be wrong with my approach of installing the add-ons? Thanks

One thing is that the baseUrl can be more than just the domain. If there is a common path that all the urls in your descriptor use, it should be here.

Your service just needs to listen to the installed webhook which will be called by Jira, and respond with a 204 No Content. You will also want to save the POST data somewhere as this contains information required to communicate with Jira

Im still getting the 404 error, it seems it is not from the /installed

Here is my atlassian-connect.json:

{“key”:“wsna-oneconnect.azurewebsites.net”,“name”:“OneConnect Project Online & Jira Integration”,“description”:“Synchronize from Jira to Project Online”,“vendor”:{“name”:“Wicresoft North America”,“url”:“https://us.wicresoft.com/"},“links”:{“self”:“https://wsna-cdn.azurewebsites.net/products/OneConnect/JIRA/OneConnect-Jira-ProjectOnline/atlassian-connect.json”},“baseUrl”:“https://wsna-cdn.azurewebsites.net/”,“authentication”:{“type”:“jwt”},“enableLicensing”:true,“lifecycle”:{“installed”:"/installed",“uninstalled”:"/uninstalled"},“scopes”:[“read”,“write”],“modules”:{“generalPages”:[{“key”:“hello-world-page-jira”,“location”:“system.top.navigation.bar”,“name”:{“value”:“OneConnect”},“url”:"/hello-world",“conditions”:[{“condition”:“user_is_logged_in”}]},{“key”:“hello-world-page-confluence”,“location”:“system.header/left”,“name”:{“value”:“OneConnect”},“url”:"/hello-world",“conditions”:[{“condition”:“user_is_logged_in”}]}]},“version”:"1.1.0-AC”}

Here is my config.json:

{
“development”: {
“port”: 3000,
“errorTemplate”: true,
// “store”: {
// “adapter”: “jugglingdb”,
// “type”: “sqlite3”,
// “database”: “store.db”
// }
},

"production": {
    "port": "$PORT",
    "errorTemplate": true,
    "localBaseUrl": "https://wsna-cdn.azurewebsites.net/products/OneConnect/JIRA/OneConnect-Jira-ProjectOnline",
    "store": {
        "type": "postgres",
        "url": "$DATABASE_URL"
    },
    "whitelist": [
        "*.jira-dev.com",
        "*.atlassian.net",
        "*.atlassian.com",
        "*.jira.com"
    ]
},
"product": "jira"

}

Here is my index.js that also handles the /installed:

module.exports = function (app, addon) {

// Root route. This route will serve the `atlassian-connect.json` unless the
// documentation url inside `atlassian-connect.json` is set
app.get('/', function (req, res) {
    res.format({
        // If the request content-type is text-html, it will decide which to serve up
        'text/html': function () {
            res.redirect('/atlassian-connect.json');
        },
        // This logic is here to make sure that the `atlassian-connect.json` is always
        // served up when requested by the host
        'application/json': function () {
            res.redirect('/atlassian-connect.json');
        }
    });
});

// This is an example route that's used by the default "generalPage" module.
// Verify that the incoming request is authenticated with Atlassian Connect
app.get('/hello-world', addon.authenticate(), function (req, res) {
        // Rendering a template is easy; the `render()` method takes two params: name of template
        // and a json object to pass the context in
        res.render('hello-world', {
            title: 'Atlassian Connect'
            //issueId: req.query['issueId']
        });
    }
);

// Add any additional route handlers you need for views or REST resources here...
app.get('/installed', function (req, res) {
     res.status(204).send({});
 });

// load any additional files you have in routes and apply those to the app
{
    var fs = require('fs');
    var path = require('path');
    var files = fs.readdirSync("routes");
    for(var index in files) {
        var file = files[index];
        if (file === "index.js") continue;
        // skip non-javascript files
        if (path.extname(file) != ".js") continue;

        var routes = require("./" + path.basename(file));

        if (typeof routes === "function") {
            routes(app, addon);
        }
    }
}

};

I put a 204 status to send back, and I tried to redirect to (’/atlassian-connect.json’) and still doesn’t work. Can it be something else? I have enabled both private listings and development mode.

Sorry I just realised that you have cdn in the URL, which I assume means that all your files are hosted on one.
If you want to make a pure front end application (only Javascript, CSS, and HTML) keep the CDN, but change the authentication.type to none and remove lifecycle from the descriptor.

Otherwise, if you need a backend, you will need to host your code somewhere else.

2 Likes

Hey dave, thanks for the reply. I just had time to finally come back at this project. I finally got it installed in one of my jira account. However, seems like the general page of the app couldn’t be load. I’m getting the “The resource you are looking for has been removed, had its name changed, or is temporarily unavailable” error. This must be some obvious mistakes somewhere I specified the general page. I’m so confused why it works when I’m using the local framework, shouldn’t it be the same? or maybe I’m missing some information from the resource that I was digging in.

Hey @dwilliams :slight_smile:

The error that you are getting now is an error from the cdn. It is unable to find the page located at https://wsna-cdn.azurewebsites.net/products/OneConnect/JIRA/OneConnect-Jira-ProjectOnline/hello-world (this is a combination of the baseUrl and module url taken from your descriptor here).

This should be adjusted to hello-world.html, and then you need to push a file to hello-world.html on your cdn, so that you could hit the url above and render it (without going through Jira)

1 Like