Custom Plugin not found after upload/activation

Hi! I uploaded a custom plugin, but while trying to execute it by calling:
http://{MatterMost_URL}/plugins/{Plugin_ID}
i got 404 not found.

Notes:
i am developing my code on windows and deploying on linux server (MatterMost server).
so, i executed these commands before build:
GOOS=linux
GOARCH=amd64

Then build using:
go build -o plugin.exe plugin.go
///////////////////////////////////////////////////////////

plugin.go code:

package main

import (
“net/http”
github.com/mattermost/mattermost-server/plugin
)

type HelloWorldPlugin struct {
plugin.MattermostPlugin
Enabled bool
Secret string
UserName string
}

func (p *HelloWorldPlugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Request) {
if !p.Enabled || p.Secret == “” || p.UserName == “” {
http.Error(w, “This plugin is not configured.”, http.StatusForbidden)
return
}
}

// This example demonstrates a plugin that handles HTTP requests which respond by greeting the
// world.
func main() {
plugin.ClientMain(&HelloWorldPlugin{})
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////

plugin.yaml:

id: com.mattermost.server-hello-world
name: Server “Hello, world!”
server:
executable: ./plugin.exe
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

I am having the exact same problem.

Hi all! Thank you for reaching out.

I saw in another post that haris confirmed he is using v5.1 and the below config settings, @karim can you help confirm details of your environment and current config settings?

"PluginSettings": {
       "Enable": true,
       "EnableUploads": true,
       "Directory": "./plugins",
       "ClientDirectory": "./client/plugins",
       "Plugins": {},
       "PluginStates": {
           "com": {
               "Enable": true

@amy.blais Do let me know if I can help debug as well. Haven’t been able to get this to work yet.

Thanks!

I have mattermost installed on my local machine by following: https://docs.mattermost.com/install/docker-local-machine.html#macos

Here is my mattermost and db version:

Mattermost Version: 5.1.0
Database Schema Version: 5.1.0
Database: mysql

Here is my docker installation’s OS and arch.

root@4bdee6a90b82:/mm/mattermost/plugins# uname -a
Linux 4bdee6a90b82 4.9.87-linuxkit-aufs #1 SMP Wed Mar 14 15:12:16 UTC 2018 x86_64 GNU/Linux

These are the tutorial steps I followed for building the executable plugin:

➜  my-plugin$ GOOS=linux GOARCH=amd64 go build -o plugin plugin.go
➜  my-plugin$ ls
plugin        plugin.go     plugin.yaml
➜  my-plugin$ file plugin
plugin: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, with debug_info, not stripped
➜  my-plugin$ cat plugin.yaml
id: com.mattermost.server-hello-world
name: Server "Hello, world!"
server:
    executable: plugin

I uploaded the plugin on http://localhost:8065/admin_console/plugins/management.

This is how my file structure looks like:

root@4bdee6a90b82:/mm/mattermost$ ls client/plugins/
root@4bdee6a90b82:/mm/mattermost$ ls plugins/
com.mattermost.server-hello-world  jira  memes	zoom

Hi @amy.blais
It is v4.9.1
and yes this is similar to my config:
“PluginSettings”: {
“Enable”: true,
“EnableUploads”: true,
“Directory”: “./plugins”,
“ClientDirectory”: “./client/plugins”,
“Plugins”: {
“jira”: {
“enabled”: null,
“secret”: null,
“username”: null
},
“mattermost-profanity-filter”: {
“censorcharacter”: “\*”,
“rejectposts”: null
},
“zoom”: {
“apikey”: null,
“apisecret”: null,
“webhooksecret”: null,
“zoomapiurl”: null,
“zoomurl”: null
}
},
“PluginStates”: {
“com.mattermost.server-hello-world”: {
“Enable”: true
},
“jira”: {
“Enable”: true
},
“mattermost-profanity-filter”: {
“Enable”: true
},
“memes”: {
“Enable”: true
}
}
}

@crspeller / @jesse Would you be able to help with this one?

Hi @karim and @haris! The sample code you’ve posted suggests you’re writing a plugin for Mattermost 5.2 and later (e.g. using ClientMain and embedding plugin.MattermostPlugin). We’ve significantly overhauled plugins in Mattermost 5.2 as we prepare to take them out of beta, and as a result, plugins written for Mattermost 5.2 won’t work on Mattermost 5.1.

I suspect if you check your server logs, you’ll see an error from Mattermost about being unable to start up the plugin. That likely explains why your ServeHTTP endpoint isn’t being called.

Mattermost 5.2 is scheduled to be released on August 16th. While I encourage you to target plugin development for same, I can understand that you may not yet be in a position to upgrade when it is released. You can find an example plugin for Mattermost 5.1 at https://github.com/mattermost/mattermost-server/blob/v5.1.0/plugin/example_hello_world_test.go that should help you get unblocked.

@jesse Oh! I believe both Karim and I took https://developers.mattermost.com/extend/plugins/server/hello-world/ to be the source of truth despite our version differences.

However, the logs does show that it was successfully able to activate the plugin though:
{"level":"info","ts":1533055427.971367,"caller":"app/plugin.go:208","msg":"Activated plugin","plugin_id":"com.mattermost.server-hello-world"}

Probably that’s what threw us both off track thinking “We’ve done everything right and there’s something wrong with the doc”.

Will definitely keep the 5.2 upgrade in the pipeline. However, for the time being, at least I have to work with 5.1 since we’ve deployed and it is fuelling business logic in full swing. :slight_smile:

Thanks for the plugin example for 5.1. Going to give that a shot right away and will report back on the thread with an update.

Thanks again @jesse, @amy.blais and @karim!

Hi @jesse
I tried with this code and same problem “plugin not found”

@jesse To get it to work, I had to checkout the mattermost-server to the v5.1.0 tag.

Built it using GOOS=linux GOARCH=amd64 go build -o plugin plugin.go.

plugin.yaml looks like:

id: com.mattermost.server-hello-world
name: Server "Hello, world!"
server:
    executable: plugin

Uploaded the tar file and successfully activated plugin. The logs show {"level":"info","ts":1533142981.2206817,"caller":"app/plugin.go:208","msg":"Activated plugin","plugin_id":"com.mattermost.server-hello-world"}.

Restarted the docker mattermost-preview.

However, visiting http://localhost:8065/plugins/com.mattermost.server-hello-world still shows 404 page not found.

Just to add to it, the zoom and meme plugins work fine on my local installation just in case you were wondering if this was because of a more general problem.

Anything I can do to help you help me further? Thanks!

Out of curiosity as well, in the 5.1 plugin example: https://github.com/mattermost/mattermost-server/blob/v5.1.0/plugin/example_hello_world_test.go, where would the fmt.Fprintf(w, "Hello, world!") be printed? I assume it is supposed to show up on the logs?

Hi Haris!

Change your plugin.yaml to specify a backend key. In Mattermost 5.2, this was changed to be consistent with the rest of the architecture and use the key server, but you’ll need to use the old key for now:

id: com.mattermost.server-hello-world
name: Server "Hello, world!"
backend:
    executable: plugin

With that change, I can compile the code and get the desired output from the HTTP endpoint. The fmt.Fprintf takes a io.Writer as its first parameter – in this case, the http.ResponseWriter, so the “Hello World!” is written as the response to the HTTP request.

@karim, I suspect there’s an issue in how your plugin is being bundled and initialized. I might suggest taking a look at https://github.com/mattermost/mattermost-developer-documentation/tree/plugins-v5.1.0/site/content/extend/plugins (tagged to the 5.1.0 version) to see if there’s something there that might help. Or if you can post a more detailed breakdown of your plugin bundling strategy, I can try to help.

With Mattermost 5.2, we’ve also launched https://github.com/mattermost/mattermost-plugin-sample and https://github.com/mattermost/mattermost-plugin-demo to better illustrate all of these details, but of course those won’t help you until you can upgrade :slight_smile:

Hey @jesse,

Thanks a ton for your patience.

I did as you suggested, built the plugin, tarred and uploaded it. Upon clicking activate however, it gave me:
This plugin failed to start. Check your system logs for errors.

The logs had this to show:

# {"level":"error","ts":1533231099.1921234,"caller":"app/plugin.go:158","msg":"Plugin failed to activate","plugin_id":"com.mattermost.server-hello-world","err":"unable to start plugin: com.mattermost.server-hello-world: fork/exec plugins/com.mattermost.server-hello-world/plugin: permission denied"}
# {"level":"error","ts":1533231100.1951332,"caller":"rpcplugin/supervisor.go:92","msg":"Plugin terminated unexpectedly","plugin_id":"com.mattermost.server-hello-world"}
# {"level":"error","ts":1533231102.1994798,"caller":"rpcplugin/supervisor.go:92","msg":"Plugin terminated unexpectedly","plugin_id":"com.mattermost.server-hello-world"}
# {"level":"error","ts":1533231107.2012076,"caller":"rpcplugin/supervisor.go:96","msg":"Plugin shutdown","plugin_id":"com.mattermost.server-hello-world","max_process_restarts":3,"error":"plugin terminated unexpectedly too many times"}

Googling hinted about the “executable” bit being set. So I tried a chmod +x on the built plugin. However, trying to Activate that after uploading gave me the error:

# {"level":"error","ts":1533230635.717955,"caller":"app/plugin.go:158","msg":"Plugin failed to activate","plugin_id":"com.mattermost.server-hello-world","err":"unable to start plugin: com.mattermost.server-hello-world: fork/exec plugins/com.mattermost.server-hello-world/plugin: exec format error"}

The troubleshooting tips at Redirect are for “failing uploads”, but my upload works fine and it is the Activate that is failing.

However, the funny part is, I tried changing the yaml file from backend back to server, built, uploaded and it got activated without any problem! The logs had:

{"level":"info","ts":1533231385.0844607,"caller":"app/plugin.go:208","msg":"Activated plugin","plugin_id":"com.mattermost.server-hello-world"}

Unfortunately, visiting http://localhost:8065/plugins/com.mattermost.server-hello-world still shows 404 not found.

Just to confirm, I am indeed running 5.1:
55%20PM

Any hints that I could try out or any other piece of information that I can give you which would let you help me?

Thanks again!

Happy to help, @haris! The Activated plugin message is misleading, because the server is seeing a plugin with basically no backend or frontend component, and “activates” nothing successfully. I’ll make sure we fix this in an upcoming release to avoid the ambiguity.

chmod u+x shouldn’t have been necessary – go is supposed to set the executable bit correctly itself. I presume your server is actually running on Linux (and not Darwin or Windows)?

The only other thing is to make sure the plugin.go file is actually using the main package. The example can’t show this, given the way godoc works, but here’s a working copy:

package main

import (
	"fmt"
	"net/http"

	"github.com/mattermost/mattermost-server/plugin/rpcplugin"
)

type HelloWorldPlugin struct{}

func (p *HelloWorldPlugin) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello, world!")
}

// This example demonstrates a plugin that handles HTTP requests which respond by greeting the
// world.
func main() {
	rpcplugin.Main(&HelloWorldPlugin{})
}

@jesse That did it! :slight_smile:

I believe I had tried the package main before, but had func Example_helloWorld instead of func main. And while trying to build, that had given me errors of the sort:

runtime.main_main·f: relocation target main.main not defined
runtime.main_main·f: undefined: "main.main"

I guess my lack of Go knowledge coupled with the slightly ambiguous plugin examples is what ended up here.

But all’s well that ends well. Thanks a ton again @jesse and @amy.blais.

@karim, and for anyone else who ends up here, here is my setup for Mattermost 5.1:

plugin.go:

package main

import (
	"fmt"
	"net/http"

	"github.com/mattermost/mattermost-server/plugin/rpcplugin"
)

type HelloWorldPlugin struct{}

func (p *HelloWorldPlugin) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello, world!")
}

// This example demonstrates a plugin that handles HTTP requests which respond by greeting the
// world.
func main() {
	rpcplugin.Main(&HelloWorldPlugin{})
}

plugin.yaml

id: com.mattermost.server-hello-world
name: Server "Hello, world!"
backend:
    executable: plugin

Built using (for Linux):

GOOS=linux GOARCH=amd64 go build -o plugin plugin.go

Tar it:

tar -czvf plugin.tar.gz plugin plugin.yaml

Upload it on mattermost, and activate it.
You should be able to see Hello, world! on http://localhost:8065/plugins/com.mattermost.server-hello-world.

@jesse On a side note, if there’s anything you want me to try out to get feedback on and / or improve documentation anywhere, do let me know. I’ve enjoyed integrating it into our workflow and with the Slack outages that happen, I see MM quickly becoming and integral part our business.

Cheers!

Thanks for confirming @haris, and for sticking in there :slight_smile:

We discussed internally as a team how we wanted to handle precisely your use case, especially given the beta nature of plugins as they were. I think we can do more here to improve the documentation experience, probably starting with getting the old documentation available on developers.mattermost.com. I’ll bring this up to see how we can improve things for you and those who follow after you!

1 Like

Thanks @jesse and @haris, it is working now :slight_smile:

2 Likes